#include "BondDetailData.h"

#include <bondlib/AdditionBondInfo.h>
#include <bondlib/BondCDCPriceInfo.h>
#include <bondlib/BondCSIPriceInfo.h>
#include <bondlib/BondContainer.h>
#include <bondlib/BondDict.h>
#include <bondlib/QBBondCrmClause.h>
#include <core/StyleMgr.h>
#include <core/Utility.h>
#include <core/sharedata/login_data.h>
#include <core/time/date.h>
#include <core/time/system_time.h>
#include <qbprotocol/include/SSQBAModel.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbtools/tools.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>

#include <QMetaType>

#include "../BondDataCenter.h"
#include "../BondUtility.h"
#include "../QbMessageProcess.h"
#include "BondDetailPrcInter.h"
#include "BondDetailTools.h"
#include "msgcenter/BondMsgProcess.h"

DetailData::DetailData(BondDetailDlg* p) : m_dlg(p) {
  m_emCurBondType = em_Broker;
  m_cdcType = detailModel_CDC_Aprismt_All;
  m_iTabDayLineType = 0;
  m_iTabQuoteDayLineType = 0;

  m_lReqExDealKLineIDEx = m_lReqExDealKLineIDBroker = m_lReqYieldCurve = -1;
  m_lReqExDealKLineIDCloseEx = m_lReqExDealKLineIDCloseBroker =
      m_lReqExDealKLineCfetsCloseEx = -1;

  m_bExchangeRight = SSUserAccountManager::instance().GetExchange_Right();
  m_bCFETSRight = SSUserAccountManager::instance().GetCFETS_Permission();
  m_mktStreamRight =
      strcmp(SSUserAccountManager::instance().GetPermission().GetValue(
                 USER_PERMISSION_BOND_MARKETSTREAM),
             "1") == 0;
  const char* right = SSUserAccountManager::instance().GetPermission().GetValue(
      USER_PERMISSION_BROKER_BESTQUOTE);
  m_hasBestQuoteRight = (right != nullptr) && (strcmp(right, "1") == 0);

  connect(&BondDataCenter::instance(), &BondDataCenter::dealMarketPush, this,
          &DetailData::onMarketDealChanged);
  if (m_mktStreamRight)
    connect(&BondDataCenter::instance(), &BondDataCenter::bestPriceArrived,
            this, &DetailData::onBestPriceArrived);

  qRegisterMetaType<xQBBestPriceSynthetical_Unit_c>(
      "xQBBestPriceSynthetical_Unit_c");
  qRegisterMetaType<std::map<std::string, int> >("std::map<string, int>");

  qbBase::getNetworkService()->RegisterNetworkEventObserver(this);
}

DetailData::~DetailData() {
  qbBase::getNetworkService()->DeRegisterNetworkEventObserver(this);
}

void DetailData::setCombondKey(const char* bondKey /*= nullptr*/,
                               int brokerId /*= -1*/) {
  if (m_combondKey == bondKey) return;

  onCombondKeyChanged(bondKey);
}

QString DetailData::crmString() const {
  if (m_crmType == crm_crm)
    return tr("标的", "DetailAuth");  // _T("标的");
  else if (m_crmType == crm_cln_refer)
    return "CLN";
  else if (m_crmType == crm_crm_refer)
    return "CRM";
  return "";
}

void DetailData::setClearSpeed(int v) {
  if (m_clearSpeed == v) return;
  m_clearSpeed = v;
  emit clearSpeedChanged();
}

void DetailData::setCrmType() {
  m_crmType = crm_null;
  m_strCrmKey = "";
  if (!m_bond.IsValidBond()) return;
  bool bIsCrmCln = false;
  if (strcmp(m_bond.GetBondSubType(), "CRM") == 0 ||
      strcmp(m_bond.GetBondSubType(), "crm") == 0) {
    m_crmType = crm_crm;
    bIsCrmCln = true;
  } else if (strcmp(m_bond.GetBondSubType(), "CLN") == 0 ||
             strcmp(m_bond.GetBondSubType(), "cln") == 0) {
    m_crmType = crm_cln;
    bIsCrmCln = true;
  }
  m_strCrmKey = "--";
  if (bIsCrmCln) {
    const BOND_CRM_CLAUSE* crmCla =
        QBCRMBond::instance().GetBondByKey(m_bond.GetBondKey());
    if (crmCla) {
      m_strCrmKey = QString::fromLocal8Bit(crmCla->ReferBondKey.c_str());
    }
  } else {
    const BOND_CRM_CLAUSE* crmRef =
        QBCRMBond::instance().GetBondByReferKey(m_bond.GetCombBondKey());
    if (crmRef) {
      CBondContainer& bc = CBondContainer::instance();
      int bondIndex = -1;
      for (int nL = 0; nL < 3; nL++) {
        if (nL == 0) {
          bondIndex = bc.GetBondIndex(crmRef->BondKey, CBondContainer::lmCIB);
        } else if (nL == 1) {
          bondIndex = bc.GetBondIndex(crmRef->BondKey, CBondContainer::lmSSE);
        } else if (nL == 2) {
          bondIndex = bc.GetBondIndex(crmRef->BondKey, CBondContainer::lmSZE);
        }
        if (bc.IsValidIndex(bondIndex)) break;
        bondIndex = -1;
      }

      if (bc.IsValidIndex(bondIndex)) {
        const CBondInfo& bi = bc.ElementAtR(bondIndex);
        if (strcmp(bi.GetBondSubType(), "CRM") == 0 ||
            strcmp(bi.GetBondSubType(), "crm") == 0) {
          m_crmType = crm_crm_refer;
        } else if (strcmp(bi.GetBondSubType(), "CLN") == 0 ||
                   strcmp(bi.GetBondSubType(), "cln") == 0) {
          m_crmType = crm_cln_refer;
        }
        m_strCrmKey = QString::fromLocal8Bit(bi.GetCombBondKey());
      }
    }
  }
}

void DetailData::getCrossMarkertInfo() {
  unSubExBestQuoteReg();

  CBondContainer& bc = CBondContainer::instance();
  int bondIndex = bc.GetBondIndex(comBondKey());

  if (!bc.IsValidIndex(bondIndex)) return;

  if (m_bond.IsCrossMarket()) {
    int bondIndex2 =
        bc.GetBondIndex(m_bond.GetBondKey(), CBondContainer::lmCIB);
    if (bc.IsValidIndex(bondIndex2) && bondIndex2 != bondIndex)
      addBondInfo(bondIndex2);

    bondIndex2 = bc.GetBondIndex(m_bond.GetBondKey(), CBondContainer::lmSSE);
    if (bc.IsValidIndex(bondIndex2) && bondIndex2 != bondIndex)
      addBondInfo(bondIndex2);

    bondIndex2 = bc.GetBondIndex(m_bond.GetBondKey(), CBondContainer::lmSZE);
    if (bc.IsValidIndex(bondIndex2) && bondIndex2 != bondIndex)
      addBondInfo(bondIndex2);

    reqAndSubExBestQuote();
  }
}

void DetailData::addBondInfo(int bondIndex) {
  const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
  CCrossMarketInfo mkt;
  FIELDCOPY(mkt.m_sBondKey, bi.GetBondKey());
  FIELDCOPY(mkt.m_sCombCode, bi.GetCombBondCode());
  FIELDCOPY(mkt.m_sListedMarket, bi.GetListedMarket());
  FIELDCOPY(mkt.m_sShorName, bi.GetBondShortName());
  m_vtCrossData.push_back(mkt);
}

void DetailData::getCompanyBondInfo() {
  const CBrokerList& brokerList =
      SSUserAccountManager::instance().GetReadonlyBroker();

  CBondContainer& bc = CBondContainer::instance();

  for (size_t i = 0; i < m_vtCrossData.size(); i++) {
    CCrossMarketInfo& mkt = m_vtCrossData[i];
    mkt.m_vtCorpId.clear();
    char strCombKey[42] = {0};
    FMTBUF(strCombKey, "%s.%s", mkt.m_sBondKey, mkt.m_sListedMarket);

    for (CBrokerList::BrokerMap::const_iterator Iter =
             brokerList.GetBrokerMap().begin();
         Iter != brokerList.GetBrokerMap().end(); ++Iter) {  // 经纪商报价
      const CBrokerUnit& stUnit = Iter->second;
      if (!CBrokerList::IsValidBroker_All(stUnit.m_brokerID)) continue;
      if (!stUnit.m_enableFlag_BOND && !stUnit.m_enableFlag_NCD) continue;

      char strcorp[10] = {0};
      FMTBUF(strcorp, "%d", stUnit.m_brokerID);
      REPORT report;
      if (bc.GetCompanyRepByKey(strCombKey, strcorp, report) &&
          (strcmp(report.m_askinfo.m_price_status, "0") != 0 ||
           strcmp(report.m_bidinfo.m_price_status, "0") != 0))
        mkt.m_vtCorpId.push_back(strcorp);
    }

    if (strcmp(mkt.m_sListedMarket, CBondContainer::lmSSE) == 0 ||
        strcmp(mkt.m_sListedMarket, CBondContainer::lmSZE) == 0) {  // 交易所
      XCQUOTE quote;
      if (bc.GetXCQuoteByKey(mkt.m_sBondKey, mkt.m_sListedMarket, quote))
        mkt.m_vtCorpId.push_back(mkt.m_sListedMarket);
    } else if (strcmp(mkt.m_sListedMarket, CBondContainer::lmCIB) ==
               0) {  // CFETS
      CFETSQUOTE quote;
      if (bc.GetCFETSQuoteByKey(mkt.m_sBondKey, mkt.m_sListedMarket,
                                CCFETSQuote::BESTPRICE, quote))
        mkt.m_vtCorpId.push_back("cfets");
      else if (bc.GetCFETSQuoteByKey(mkt.m_sBondKey, mkt.m_sListedMarket,
                                     CCFETSQuote::MARKETMAKER, quote))
        mkt.m_vtCorpId.push_back("cfets");
      else if (bc.GetCFETSQuoteByKey(mkt.m_sBondKey, mkt.m_sListedMarket,
                                     CCFETSQuote::XBOND, quote))
        mkt.m_vtCorpId.push_back("cfets");
    }
  }
}

bool DetailData::isShowYieldChart() {
  if (!m_bond.is_interest_bond()) {
    if (m_bond.CheckCommonUseType(CBondContainer::CommRailWay)) {
      return true;
    }
    return false;
  }
  return m_bond.is_interest_bond();
}

int DetailData::getWndType() {
  xQBIssuerCreditSpreadAck* pIssuerData = BondDetailCache::instance()
                                              .getChart(m_bond.GetIssuerCode())
                                              .m_pInterestIssuer;
  xQBBondCreditSpreadAck* pBondData = BondDetailCache::instance()
                                          .getChart(m_bond.GetCombBondKey())
                                          .m_pInterestBond;

  bool bHaveBond = pBondData && pBondData->m_list.size() > 0;
  bool bHaveIssuer = pIssuerData && pIssuerData->m_list.size() > 0;

  if (bHaveBond && bHaveIssuer)
    return wndTp_Both;
  else if (bHaveBond)
    return wndTp_Bond;
  else if (bHaveIssuer)
    return wndTp_Issuer;
  else
    return wndTp_Null;
}

void DetailData::GetChartMktStreamData(xQBMarketStreamList_c& mkt) {
  std::map<int, xQBMarketStreamUnit_c> mapTemp;
  if (m_emCurBondType == em_CFETS) {
    mapTemp = cfetsMarketStream();
  } else {
    mapTemp = marketStream();
  }

  for (std::map<int, xQBMarketStreamUnit_c>::const_iterator itr =
           mapTemp.begin();
       itr != mapTemp.end(); itr++) {
    if (IsValidChartData(itr->second)) {
      mkt.m_List.push_back(itr->second);
    }
  }
  mkt.m_List.sort();
}

void DetailData::GetChartMktStreamDealData(xQBMarketStreamList_c& mkt) {
  std::map<std::string, xQBMarketStreamUnit_c> mapTemp;
  mapTemp = marketDeal();
  for (std::map<std::string, xQBMarketStreamUnit_c>::const_iterator itr =
           mapTemp.begin();
       itr != mapTemp.end(); itr++) {
    if (IsValidChartData(itr->second)) {
      mkt.m_List.push_back(itr->second);
    }
  }
  mkt.m_List.sort();
}

bool DetailData::IsValidChartData(const xQBMarketStreamUnit_c& unt) {
  if (m_emCurBondType == em_Exchange) {
    // 过滤掉非匹配的成交
    if (strcmp(unt.m_company_id, "e") == 0) {
      {
        if (atoi(unt.m_body2.m_tradeMode) > 1) return false;  // 过滤非匹配成交
      }
      return true;
    } else
      return false;
  } else if (m_emCurBondType == em_CFETS) {
    return true;
  } else if (atoi(unt.m_type) == 2 && atoi(unt.m_body2.m_dealStatus) == 8) {
    return false;
  }

  int nBroker = atoi(unt.m_company_id);
  if (m_mapBrokerAuthority.find(nBroker) == m_mapBrokerAuthority.end()) {
    bool bBroker = false;  // 判断是否有broker权限
    const CBrokerList& brokerlist =
        SSUserAccountManager::instance().GetReadonlyBroker();
    for (CBrokerList::BrokerMap::const_iterator itor =
             brokerlist.GetBrokerMap().begin();
         itor != brokerlist.GetBrokerMap().end(); ++itor) {
      if (itor->second.m_brokerID == nBroker &&
          (itor->second.m_enableFlag_BOND || itor->second.m_enableFlag_NCD)) {
        bBroker = true;
        break;
      }
    }
    m_mapBrokerAuthority[nBroker] = bBroker;
  }
  return m_mapBrokerAuthority[nBroker];
}

std::map<int, xQBMarketStreamUnit_c> DetailData::marketStream() const {
  std::map<int, xQBMarketStreamUnit_c> mapUnit = m_mapMktStream;

  if (m_clearSpeed > 0) {
    auto iter = mapUnit.begin();
    for (; iter != mapUnit.end();) {
      bool succeed = BondUtility::updateMarketStreamBySettlement(
          iter->second, m_clearSpeed, false, false);
      if (!succeed) {
        iter = mapUnit.erase(iter);
        continue;
      }
      ++iter;
    }
  }

  return mapUnit;
}

std::map<int, xQBMarketStreamUnit_c> DetailData::cfetsMarketStream() const {
  std::map<int, xQBMarketStreamUnit_c> mapUnit = m_mapCfetsMktStream;

  if (m_clearSpeed > 0) {
    auto iter = mapUnit.begin();
    for (; iter != mapUnit.end();) {
      bool succeed = BondUtility::updateMarketStreamBySettlement(
          iter->second, m_clearSpeed, false, true);
      if (!succeed) {
        iter = mapUnit.erase(iter);
        continue;
      }
      ++iter;
    }
  }

  return mapUnit;
}

static void FormatString(QString& str, const char* input,
                         const QString& defStr = "--") {
  if (strlen(input) <= 0)
    str = defStr;
  else
    str = QString::fromLocal8Bit(input);
}

static QString FormatAppDate(int uDate) {
  QString strReturn = "";
  if (uDate < 1) return strReturn;
  if (uDate > 10000) {
    strReturn = QString("%1/%2").arg(uDate / 100 % 100).arg(uDate % 100);
  }
  return strReturn;
}
void DetailData::fillTitleParam() {
  m_titleParams.m_companyName =
      QString::fromLocal8Bit(m_bond.GetInstitutionFullName());
  // 中债
  bool bIsCDCAuthValid = m_bond.IsCDCAuthValid();
  if (!bIsCDCAuthValid) {
    if (m_bond.GetCdcAuth() < 0)
      m_titleParams.m_strApp = "";  // 中债权限表中无对应债券
    else
      m_titleParams.m_strApp = tr("无权限", "DetailAuth");
  } else {
    getSpecialCDC();
  }
  FormatString(m_titleParams.m_strRemain,
               m_bond.GetRemainPeriod(ServerTimeMgr::instance().serverTime()));

  if (strcmp(m_bond.GetIssuerRating(), "CCL") == 0)
    m_titleParams.m_strIssuer = "--";
  else
    FormatString(m_titleParams.m_strIssuer, m_bond.GetIssuerRating());
  if (strcmp(m_bond.GetBondRating(), "CCL") == 0)
    m_titleParams.m_strRating = "--";
  else
    FormatString(m_titleParams.m_strRating, m_bond.GetBondRating());

  if (!SSUserAccountManager::instance().HasAuthOfCBR()) {
    m_titleParams.m_strChinaDCRating = tr("无权限", "DetailAuth");
  } else {
    FormatString(m_titleParams.m_strChinaDCRating, m_bond.GetCBRRating());
    m_titleParams.m_strChinaDCState = "--";
    if (strcmp(m_bond.GetChinaDCState(), "POS") == 0) {  // 正面
      m_titleParams.m_strChinaDCState =
          tr("正面", "BDPublisherGrade");                       //_T("正面");
    } else if (strcmp(m_bond.GetChinaDCState(), "STB") == 0) {  // 稳定
      m_titleParams.m_strChinaDCState =
          tr("稳定", "BDPublisherGrade");                       //_T("稳定");
    } else if (strcmp(m_bond.GetChinaDCState(), "NEG") == 0) {  // 负面
      m_titleParams.m_strChinaDCState =
          tr("负面", "BDPublisherGrade");                       //_T("负面");
    } else if (strcmp(m_bond.GetChinaDCState(), "RWT") == 0) {  // 列入观察
      m_titleParams.m_strChinaDCState =
          tr("列入观察", "BDPublisherGrade");  //_T("列入观察");
    }
  }
  // 中证
  if (!SSUserAccountManager::instance().GetCSIAuthorityFlag()) {
    m_titleParams.m_strZZ = tr("无权限", "DetailAuth");
  } else {
    UINT nType = 0;
    QString szYield, szCleanPrice;

    // TODO:请求该数据
    xCSIUint_c xUnit;
    if (CBondCSInfo::instance().GetCsiUnit(m_bond.GetCombBondKey(), xUnit)) {
      if (xUnit.IsHaveYieldToExercise()) {
        szYield = QString("%1(%2)")
                      .arg(xUnit.m_dYieldToExercise, 0, 'f', 4)
                      .arg(tr("行权", "EstRemark"));
      } else if (xUnit.IsHaveMarturity()) {
        if (xUnit.IsHaveYieldToMarturity()) {
          szYield = QString("%1").arg(xUnit.m_dYieldToMaturity, 0, 'f', 4);
        }
      }

      if (xUnit.IsHaveCleanPriceExercise()) {
        szCleanPrice =
            QString("%1").arg(xUnit.m_dCleanPriceExercise, 0, 'f', 4);
      } else if (xUnit.IsHaveCleanPriceMarturity()) {
        szCleanPrice =
            QString("%1").arg(xUnit.m_dCleanPriceMaturity, 0, 'f', 4);
      }

      m_titleParams.m_strZZDate = FormatAppDate(xUnit.m_nDate);
    }

    FormatString(m_titleParams.m_strZZ, szYield.toLocal8Bit().data());
    FormatString(m_titleParams.m_strZZClean, szCleanPrice.toLocal8Bit().data());
  }

  if (strcmp("DSC", m_bond.GetCouponType()) == 0)  // 利率方式为贴现
  {
    m_titleParams.m_strInterest =
        QString::fromLocal8Bit(m_bond.GetIssueRate());  // 票面利率显示发行收益
    m_titleParams.m_strInterest.append("%");
  } else if (strlen(m_bond.GetCouponRateCurrent()) > 0) {
    m_titleParams.m_strInterest = BondUtility::FormatBidLimitTop(
        QString::fromLocal8Bit(m_bond.GetCouponRateCurrent()));
    m_titleParams.m_strInterest.append("%");
  } else
    m_titleParams.m_strInterest = "--";

  /*中债隐含评级 added by shiy20210719*/
  if (!SSUserAccountManager::instance().HasAuthOfCDC())  // 是否有中债权限
  {
    m_titleParams.m_strCDCImplied = tr("无权限", "DetailAuth");
  } else {
    if (strlen(m_bond.GetCDCRating()) == 0 ||
        strcmp(m_bond.GetCDCRating(), "CCL") == 0) {
      m_titleParams.m_strCDCImplied = "--";
    } else {
      m_titleParams.m_strCDCImplied =
          QString::fromLocal8Bit(m_bond.GetCDCRating());
    }
  }

  BondDict dict;
  CBondDict::instance().GetBondDict("Coupon_Type", m_bond.GetCouponType(),
                                    dict);
  m_titleParams.m_strRatePattern =
      QString::fromLocal8Bit(dict.selective_content);
  /*end*/
}

void DetailData::reqBasicData() {
  // 单券行情
  if (strlen(m_hisReq.BondKey) > 0) {
    PushMsgInfo pmi(E_FID_QB_HIS_SINGLE_DEAL_REG, m_hisReqParam, nullptr);
    unRegistPush(pmi);
  }

  FIELDCOPY(m_hisReq.BondKey, m_bond.GetBondKey());
  FIELDCOPY(m_hisReq.ListedMarket, m_bond.GetListedMarket());
  FIELDCOPY(m_hisReq.m_Source, "b");
  qb::SSRequestMsg msg;
  msg.m_pRequest = &m_hisReq;
  msg.m_FuncID = E_FID_QB_HIS_SINGLE_DEAL_REQ;
  MessagePoster poster(&msg, qbbond::makeHisSingleDealReq);
  poster.send(this);

  m_hisReqParam.clear();
  m_hisReqParam.append(m_hisReq.BondKey)
      .append("|")
      .append(m_hisReq.ListedMarket)
      .append("|")
      .append(m_hisReq.m_Source);
  PushMsgInfo pmi(E_FID_QB_HIS_SINGLE_DEAL_REG, m_hisReqParam,
                  qbbond::notifyHisSingleDealByParam);
  registPush(pmi, &msg, qbbond::makeHisSingleDealReq);

  // 发行人信息
  qb::SSRequestMsg msgIssuer;
  msgIssuer.m_pRequest = nullptr;
  msgIssuer.m_FuncID = E_FID_QB_BOND_GRADE_INSTITUTION_REQ;
  MessagePoster posterIssuer(
      &msgIssuer, [=](qb::proto::Message& msg, qb::SSRequestMsg*) {
        qb::proto::VariantMap submsg;
        qb::proto::Message::List bdList;
        qb::proto::VariantMap mpUnit;
        mpUnit.setString("BondKey", m_bond.GetBondKey());
        mpUnit.setString("ListedMarket", m_bond.GetListedMarket());
        bdList.push_back(mpUnit);

        submsg.SetList("List", bdList);
        msg.SetMap("xQBBondGradeInstitutionReq", submsg);
      });
  posterIssuer.send(this);

  reqDealData();
  // 图表数据
  reqChartData();
}

void DetailData::reqChartData() {
  BondDetailChartData& data =
      BondDetailCache::instance().getChart(m_bond.GetCombBondKey());
  reqDealChartData(data);
  reqRateChartData(data);
  reqInterestChartData(data);
  reqCDCChartData(data);
}

void DetailData::reqDealChartData() {
  BondDetailChartData& data =
      BondDetailCache::instance().getChart(m_bond.GetCombBondKey());
  reqDealChartData(data);
  reqDealData();
}

void DetailData::reqDealChartData(BondDetailChartData& data) {
  em_NewDetail type = detailModel_Default;

  if (m_emCurBondType == em_Exchange) {  // 交易所
    if (m_iTabDayLineType == 0) {
      if (!data.m_pDealCurveKLineEx) {
        data.m_pDealCurveKLineEx = new xQBABrokerDealKlineDayList_c;
        if (data.m_pDealCurveKLineEx)
          FIELDCOPY(
              data.m_pDealCurveKLineEx->m_markettype,
              NEW_DETAIL_EXCHANGE_BROKER_STRING);  // exchange交易所--必须初始化！
        type = detailModel_DealCurveKLineEx;
      } else {
        m_pDataDayKline = data.m_pDealCurveKLineEx;
        emit dealChartKLineChanged(detailModel_DealCurveKLineEx);
        return;
      }

      reqChartData(type);
    }
    if (m_iTabDayLineType == 1 || m_iTabQuoteDayLineType == 0) {
      if (!data.m_pDealKlineDayCloseEx) {
        data.m_pDealKlineDayCloseEx = new xQBABrokerKlineDayCloseList_Ack;
        if (data.m_pDealKlineDayCloseEx)
          FIELDCOPY(
              data.m_pDealKlineDayCloseEx->m_markettype,
              NEW_DETAIL_EXCHANGE_BROKER_STRING);  // exchange交易所--必须初始化！
        type = detailModel_DealCurveKLineCloseEx;
      } else {
        m_pDataCloseDayKline = data.m_pDealKlineDayCloseEx;
        emit dealChartKLineChanged(detailModel_DealCurveKLineCloseEx);
        return;
      }

      reqChartData(type);
    }
  } else if (m_emCurBondType == em_CFETS) {
    if (m_iTabDayLineType == 0) {
      if (!data.m_pDealCurveKLineCFETS) {
        data.m_pDealCurveKLineCFETS = new xQBABrokerDealKlineDayList_c;
        if (data.m_pDealCurveKLineCFETS)
          FIELDCOPY(data.m_pDealCurveKLineCFETS->m_markettype,
                    NEW_DETAIL_CFETS_BROKER_STRING);
        type = detailModel_DealCurveKLineCFETS;
      } else {
        m_pDataDayKline = data.m_pDealCurveKLineCFETS;
        emit dealChartKLineChanged(detailModel_DealCurveKLineCFETS);
        return;
      }

      reqChartData(type);
    }
    if (m_iTabDayLineType == 1 || m_iTabQuoteDayLineType == 0) {
      if (!data.m_pCfetsDealKlineCfetsDayClose) {
        data.m_pCfetsDealKlineCfetsDayClose =
            new xQBABrokerKlineDayCloseList_Ack;
        if (data.m_pCfetsDealKlineCfetsDayClose)
          FIELDCOPY(data.m_pCfetsDealKlineCfetsDayClose->m_markettype,
                    NEW_DETAIL_CFETS_BROKER_STRING);
        type = detailModel_DealCurveKLineCloseCFETS;
      } else {
        m_pDataCloseDayKline = data.m_pCfetsDealKlineCfetsDayClose;
        emit dealChartKLineChanged(detailModel_DealCurveKLineCloseCFETS);
        return;
      }

      reqChartData(type);
    }
  } else {
    if (m_iTabDayLineType == 0) {
      if (!data.m_pDealCurveKLineBroker) {
        data.m_pDealCurveKLineBroker = new xQBABrokerDealKlineDayList_c;
        if (data.m_pDealCurveKLineBroker)
          FIELDCOPY(data.m_pDealCurveKLineBroker->m_markettype, "b");
        type = detailModel_DealCurveKLineBroker;
      } else {
        m_pDataDayKline = data.m_pDealCurveKLineBroker;
        emit dealChartKLineChanged(detailModel_DealCurveKLineBroker);
        return;
      }

      reqChartData(type);
    }
    if (m_iTabDayLineType == 1 || m_iTabQuoteDayLineType == 0) {
      if (!data.m_pBrokerDealKlineBrokerDayClose) {
        data.m_pBrokerDealKlineBrokerDayClose =
            new xQBABrokerKlineDayCloseList_Ack;
        if (data.m_pBrokerDealKlineBrokerDayClose)
          FIELDCOPY(data.m_pBrokerDealKlineBrokerDayClose->m_markettype, "b");
        type = detailModel_DealCurveKLineCloseBroker;
      } else {
        m_pDataCloseDayKline = data.m_pBrokerDealKlineBrokerDayClose;
        emit dealChartKLineChanged(detailModel_DealCurveKLineCloseBroker);
        return;
      }

      reqChartData(type);
    }
  }

  if (!data.m_pKlintDayCloseBoList) {
    data.m_pKlintDayCloseBoList = new xQBABrokerKlineDayCloseBoList_c;
    type = detailModel_DealCurveKLineCloseQuote;
  } else {
    m_pDataDayCloseBoKline = data.m_pKlintDayCloseBoList;
    emit dealChartKLineChanged(detailModel_DealCurveKLineCloseQuote);
    return;
  }

  reqChartData(type);
}

void NotifyByParamExBestQuote(const qb::SSAckMsg& msg, NotifyFunc notify) {
  xQBBestPriceListAck_c* pAck = (xQBBestPriceListAck_c*)msg.m_pRet;
  if (!pAck) return;

  // QString strParam =
  // QString("%1|%2.%3").arg(msg.m_FuncID).arg(pAck->m_bondkey).arg(pAck->m_listedmarket);
  // notify({ msg.m_FuncID, strParam.toStdString(), nullptr }, msg);
}

static std::string makeExBestQuoteRegParam(const TW_BOND& bond) {
  QString str = QString("%1|%2.%3")
                    .arg(E_FID_QB_EX_BEST_QUOTE_PUSH)
                    .arg(bond.m_BondKey)
                    .arg(bond.m_ListedMarket);
  return str.toStdString();
}

void DetailData::reqAndSubExBestQuote() {
  const CBondInfo& bi = this->bond();
  if (strcmp(bi.GetListedMarket(), CBondContainer::lmCIB) == 0) return;

  TW_BOND bond;
  FIELDCOPY(bond.m_BondKey, bi.GetBondKey());
  FIELDCOPY(bond.m_ListedMarket, bi.GetListedMarket());

  QBQuoteQuery_t stReq;
  stReq.m_Bond.push_back(bond);
  // 先请求历史
  {
    SSRequestMsg msg;
    msg.m_pRequest = &stReq;
    msg.m_FuncID = E_FID_QB_EX_BEST_QUOTE_QUERY;
    MessagePoster poster(&msg, qbmsg::bond::EncodeFunc);
    poster.send(this);
  }

  // 再推送
  {
    SSRequestMsg msg;
    msg.m_FuncID = E_FID_QB_EX_BEST_QUOTE_PUSH;
    msg.m_pRequest = &stReq;

    for (auto bond : stReq.m_Bond) {  // Todo:暂时未成功订阅推送
      registPush({E_FID_QB_EX_BEST_QUOTE_PUSH, makeExBestQuoteRegParam(bond),
                  NotifyByParamExBestQuote},
                 &msg, qbbond::makeExchangeQuoteReq);
    }
  }
}

void DetailData::unSubExBestQuoteReg() {
  SSRequestMsg msg;
  msg.m_FuncID = E_FID_QB_EX_BEST_QUOTE_PUSH_CANCEL;
  if (!m_req.m_Bond.empty()) {
    msg.m_pRequest = &m_req;

    for (auto bond : m_req.m_Bond) {  // Todo:暂时未成功取消订阅推送
      unRegistPush({E_FID_QB_EX_BEST_QUOTE_PUSH, makeExBestQuoteRegParam(bond),
                    NotifyByParamExBestQuote},
                   &msg, qbbond::makeExchangeQuoteReq);
    }
    m_req.m_Bond.clear();
  }
}

void DetailData::reqRateChartData(BondDetailChartData& data) {
  auto& auth = SSUserAccountManager::instance().GetCDCAutority();
  if (auth.find(8) == auth.end()) return;

  em_NewDetail type = detailModel_YieldCurve;

  if (!data.m_pYieldCurve) {
    const char* pType = m_bond.GetYieldCurveType();
    if (pType &&
        strlen(pType) >
            0)  // 只有收益率类型不为空时才申请内存并发送请求，否则将不发送请求
    {
    } else {
      return;
    }

    data.m_pYieldCurve = new CAnalysisYieldCurve;
  } else {
    emit rateChartChanged();
    return;
  }

  reqChartData(type);
}

void DetailData::reqInterestChartData(BondDetailChartData& data) {
  BondDetailChartData& data2 =
      BondDetailCache::instance().getChart(m_bond.GetIssuerCode());
  if (!data2.m_pInterestIssuer) {
    data2.m_pInterestIssuer = new xQBIssuerCreditSpreadAck;
    FIELDCOPY(data2.m_pInterestIssuer->m_issuer_code, m_bond.GetIssuerCode());
    reqChartData(detailModel_InterestIssuer);
  } else {
    emit interestChartChanged();
  }

  if (!data.m_pInterestBond) {
    data.m_pInterestBond = new xQBBondCreditSpreadAck;
    FIELDCOPY(data.m_pInterestBond->m_bond_key, m_bond.GetBondKey());
    FIELDCOPY(data.m_pInterestBond->m_listed_market, m_bond.GetListedMarket());
    reqChartData(detailModel_InterestBond);
  } else if (m_bond.IsAddIssueBond()) {
    CAdditionBondInfo* addInfo =
        const_cast<CAdditionBondInfo*>(m_bond.GetAdditionInfo());
    QString strFirstKey = QString("%1").arg(addInfo->GetFirstIssueKey());
    if (!strFirstKey.isEmpty() && strcmp(strFirstKey.toStdString().c_str(),
                                         m_bond.GetCombBondKey()) != 0) {
      if (BondDetailCache::instance().hasCache(strFirstKey.toStdString())) {
        BondDetailChartData& tempData =
            BondDetailCache::instance().getChart(strFirstKey.toStdString());
        if (tempData.m_pInterestBond) {
          xQBBondCreditSpreadAck sNew = *(tempData.m_pInterestBond);
          *(data.m_pInterestBond) = sNew;
        } else {
          int bondIndex = CBondContainer::instance().GetBondIndex(
              strFirstKey.toStdString().c_str());
          if (CBondContainer::instance().IsValidIndex(bondIndex)) {
            reqChartData(detailModel_InterestBond, bondIndex);
            return;
          }
        }
      }

      FIELDCOPY(data.m_pInterestBond->m_bond_key, m_bond.GetBondKey());
      FIELDCOPY(data.m_pInterestBond->m_listed_market,
                m_bond.GetListedMarket());

      emit interestChartChanged();
    }
  } else {
    emit interestChartChanged();
  }
}

// 上证固收五档请求
void DetailData::reqSHFIData(bool push) {
  if (!m_bExchangeRight) return;
  const CBondInfo& bi = bond();
  if (!bi.IsValidBond()) return;

  if (strcmp(bi.GetListedMarket(), CBondContainer::lmSSE) != 0) return;

  if (push) {
    QBSHFIQuoteQuery_t stReq;
    FIELDCOPY(stReq.m_BondKey, bi.GetBondKey());
    FIELDCOPY(stReq.m_ListedMarket, bi.GetListedMarket());
    // 先请求历史
    {
      SSRequestMsg msg;
      msg.m_pRequest = &stReq;
      msg.m_FuncID = E_FID_QB_SHFI_SINGLE_QUOTE_REQ;
      MessagePoster poster(&msg, qbmsg::bond::EncodeFunc);
      poster.send(this);
    }

    // 再推送
    {
      SSRequestMsg msg;
      msg.m_FuncID = E_FID_QB_SHFI_SINGLE_QUOTE_PUSH;
      msg.m_pRequest = &stReq;

      // const QString str =
      // QString("%1|%2.%3").arg(E_FID_QB_EX_BEST_QUOTE_PUSH)
      //                   .arg(bi.GetBondKey()).arg(bi.GetListedMarket());

      registPush({E_FID_QB_SHFI_SINGLE_QUOTE_PUSH, "", nullptr}, &msg,
                 qbmsg::bond::EncodeFunc);
    }
  } else {
    QBSHFIQuoteQuery_t stReq;
    FIELDCOPY(stReq.m_BondKey, bi.GetBondKey());
    FIELDCOPY(stReq.m_ListedMarket, bi.GetListedMarket());
    {
      SSRequestMsg msg;
      msg.m_pRequest = &stReq;
      msg.m_FuncID = E_FID_QB_SHFI_SINGLE_QUOTE_PUSH_CANCEL;
      MessagePoster poster(&msg, qbmsg::bond::EncodeFunc);
      poster.send();
    }
  }
}

void DetailData::reqExchangeData(bool push) {
  if (!m_bExchangeRight) return;
  const CBondInfo& bi = bond();
  if (!bi.IsExchange()) return;

  TW_BOND bond;
  memset(&bond, 0, sizeof(TW_BOND));
  FIELDCOPY(bond.m_BondKey, bi.GetBondKey());
  FIELDCOPY(bond.m_ListedMarket, bi.GetListedMarket());
  QBExQuoteQuery_t stReq;
  stReq.m_Bond.push_back(bond);

  auto EncodeFunc = [](qb::proto::Message& msg, qb::SSRequestMsg* req) {
    qb::proto::Message::List sublist;
    QBExQuoteQuery_t* pdata = (QBExQuoteQuery_t*)req->m_pRequest;
    for (std::list<TW_BOND>::const_iterator it = pdata->m_Bond.begin();
         it != pdata->m_Bond.end(); ++it) {
      qb::proto::VariantMap listmsg;
      listmsg.SetString("Bond_Type", it->m_Bond_Type);
      listmsg.SetString("BondID", it->m_BondID);
      listmsg.SetString("BondKey", it->m_BondKey);
      listmsg.SetString("ListedMarket", it->m_ListedMarket);
      sublist.push_back(listmsg);
    }
    msg.SetList("IMQ_BondKeys", sublist);
    char message_type[128] = "";
    FMTBUF(message_type, "%d", req->m_FuncID);
    msg.SetType(message_type);
  };

  if (push) {
    {
      SSRequestMsg msg;
      msg.m_pRequest = &stReq;
      msg.m_FuncID = E_FID_QB_EX_QUOTE_QUERY;  // E_FID_QB_EX_QUOTE_PUSH_V2
      MessagePoster poster(&msg, EncodeFunc);
      poster.send(this);
    }
    {
      SSRequestMsg msg;
      msg.m_pRequest = &stReq;
      msg.m_FuncID = E_FID_QB_EX_QUOTE_PUSH;

      registPush({E_FID_QB_EX_QUOTE_PUSH, "", nullptr}, &msg, EncodeFunc);
    }
  } else {
    SSRequestMsg msg;
    msg.m_pRequest = &stReq;
    msg.m_FuncID = E_FID_QB_EX_QUOTE_PUSH_CANCEL;
    MessagePoster poster(&msg, EncodeFunc);
    poster.send();
  }
}

void DetailData::reqCDCChartData(BondDetailChartData& data) {
  switch (m_cdcType) {
    case detailModel_CDC_Aprismt_30Day:
    case detailModel_CDC_Aprismt_HalfYear:
    case detailModel_CDC_Aprismt_Year:
    case detailModel_CDC_Aprismt_90Day:
    case detailModel_CDC_Aprismt_All:
    case detailModel_SQS_Aprismt_30Day:
    case detailModel_SQS_Aprismt_HalfYear:
    case detailModel_SQS_Aprismt_Year:
    case detailModel_ZZ_Aprismt_30Day:
    case detailModel_ZZ_Aprismt_Year: {
      if (m_bond.IsAddIssueBond()) {
        QString strReqKey = BondUtility::GetReqDataCombKey(&m_bond);
        if (!strReqKey.isEmpty()) {
          BondDetailChartData& dataFirst =
              BondDetailCache::instance().getChart(strReqKey.toStdString());
          if (!dataFirst.m_pAaprismtHisData) {
            dataFirst.m_pAaprismtHisData = new BondAprismtHistoryData;
          }

          int bondIndex = CBondContainer::instance().GetBondIndex(
              strReqKey.toStdString().c_str());
          if (!CBondContainer::instance().IsValidIndex(bondIndex)) return;
          const CBondInfo& bondInfo =
              CBondContainer::instance().ElementAtR(bondIndex);
          reqAppraisementData(m_cdcType, strReqKey.toStdString().c_str(),
                              bondInfo);
        } else {
          emit cdcChartChanged();
        }
      } else {
        if (!data.m_pAaprismtHisData) {
          data.m_pAaprismtHisData = new BondAprismtHistoryData;
        }
        reqAppraisementData(m_cdcType, m_bond.GetCombBondKey(), m_bond);
      }
    } break;
    default:
      break;
  }
}

void DetailData::reqChartData(em_NewDetail type, int bondIndex) {
  switch (type) {
    case detailModel_DealCurveKLineEx:  // 成交日线
    case detailModel_DealCurveKLineBroker:
    case detailModel_DealCurveKLineCFETS: {
      qb::SSRequestMsg msg;
      msg.m_pRequest = nullptr;
      msg.m_MsgType = SSReqType_Message;

      if (type == detailModel_DealCurveKLineCFETS) {
        msg.m_FuncID = E_FID_QB_CFETS_DEAL_DAYLINE_QUERY;
        if (strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) == 0) {
          MessagePoster poster(
              &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
                qb::proto::VariantMap submsg;
                submsg.setString("bond_key", m_bond.GetBondKey());
                submsg.setString("listed_market", m_bond.GetListedMarket());
                submsg.setString("companyid", NEW_DETAIL_CFETS_BROKER_STRING);
                submsg.setInt32("beginDate", -1);
                submsg.setInt32("endDate", -1);
                msg.SetMap("QBCFETSDealDaylineReq", submsg);
              });
          poster.send(this);
        }
      } else {
        msg.m_FuncID = E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ;
        MessagePoster poster(
            &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
              qb::proto::VariantMap submsg;
              submsg.setString("bond_key", m_bond.GetBondKey());
              submsg.setString("listed_market", m_bond.GetListedMarket());
              submsg.setString("market_type", "b");
              submsg.setUint32("beginDate",
                               BondUtility::getBondDetailKlineBeginTime());
              submsg.setUint32("endDate", -1);
              msg.SetMap("xQBABrokerKlineDayReq", submsg);
            });

        m_lReqExDealKLineIDBroker = poster.send(this);

        if (strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) != 0) {
          qb::SSRequestMsg msg2;
          msg2.m_pRequest = nullptr;
          msg2.m_MsgType = SSReqType_Message;
          msg2.m_FuncID = E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ;
          MessagePoster poster2(
              &msg2, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
                qb::proto::VariantMap submsg;
                submsg.setString("bond_key", m_bond.GetBondKey());
                submsg.setString("listed_market", m_bond.GetListedMarket());
                submsg.setString("market_type", "e");
                submsg.setUint32("beginDate", -1);
                submsg.setUint32("endDate", -1);
                msg.SetMap("xQBABrokerKlineDayReq", submsg);
              });

          m_lReqExDealKLineIDEx = poster2.send(this);
        }
      }
    } break;
    case detailModel_InterestBond: {
      xQBBondCreditSpreadReq req;

      if (CBondContainer::instance().IsValidIndex(bondIndex)) {
        const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
        FIELDCOPY(req.m_bond_key, bi.GetBondKey());
        FIELDCOPY(req.m_listed_market, bi.GetListedMarket());
      } else {
        FIELDCOPY(req.m_bond_key, m_bond.GetBondKey());
        FIELDCOPY(req.m_listed_market, m_bond.GetListedMarket());
      }
      req.m_date_begin = BondUtility::GetInterestBeginTime(
          m_bond, E_FID_QB_BOND_CREDIT_SPREAD_REQ);
      req.m_date_end = -1;

      if (req.m_date_begin >= -1) {
        qb::SSRequestMsg msg;
        msg.m_pRequest = &req;
        msg.m_FuncID = E_FID_QB_BOND_CREDIT_SPREAD_REQ;
        msg.m_MsgType = SSReqType_Message;
        MessagePoster poster(
            &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
              xQBBondCreditSpreadReq* pData =
                  (xQBBondCreditSpreadReq*)stReq->m_pRequest;
              qb::proto::VariantMap submsg;
              submsg.SetString("bond_key", pData->m_bond_key);
              submsg.SetString("listed_market", pData->m_listed_market);
              submsg.SetInt32("date_begin", pData->m_date_begin);
              submsg.SetInt32("date_end", pData->m_date_end);
              msg.SetMap("xQBBondCreditSpreadReq", submsg);
            });
        poster.send(this);
      }
    } break;
    case detailModel_InterestIssuer: {
      if (BondUtility::GetInterestBeginTime(
              m_bond, E_FID_QB_ISSUER_CREDIT_SPREAD_REQ) >= -1) {
        qb::SSRequestMsg msg;
        msg.m_pRequest = nullptr;
        msg.m_FuncID = E_FID_QB_ISSUER_CREDIT_SPREAD_REQ;
        msg.m_MsgType = SSReqType_Message;
        MessagePoster poster(
            &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
              qb::proto::VariantMap submsg;
              submsg.SetString("issuer_code", m_bond.GetIssuerCode());
              submsg.setInt32("date_begin",
                              BondUtility::GetInterestBeginTime(
                                  m_bond, E_FID_QB_ISSUER_CREDIT_SPREAD_REQ));
              submsg.setInt32("date_end", -1);
              msg.SetMap("xQBIssuerCreditSpreadReq", submsg);
            });
        poster.send(this);
      }
    } break;
    case detailModel_DealCurveKLineCloseEx:  // 成交曲线日线收盘:分交易所、银行间,CFETS
    case detailModel_DealCurveKLineCloseBroker:
    case detailModel_DealCurveKLineCloseCFETS: {
      qb::SSRequestMsg msg;
      msg.m_pRequest = nullptr;
      msg.m_FuncID = E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ;
      msg.m_MsgType = SSReqType_Message;
      MessagePoster poster(&msg, [=](qb::proto::Message& msg,
                                     qb::SSRequestMsg* stReq) {
        qb::proto::VariantMap submsg;
        submsg.setString("bond_key", m_bond.GetBondKey());
        submsg.setString("listed_market", m_bond.GetListedMarket());
        submsg.setString("market_type", "b");
        submsg.setInt32("beginDate",
                        BondUtility::getBondDetailKlineBeginTime());
        submsg.setInt32("endDate", qb::base::IntDate::timeToInt(time(nullptr)));
        msg.SetMap("xQBABrokerKlineDayCloseReq", submsg);
      });
      m_lReqExDealKLineIDCloseBroker = poster.send(this);

      if (strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) != 0) {
        qb::SSRequestMsg msg2;
        msg2.m_pRequest = nullptr;
        msg2.m_FuncID = E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ;
        msg2.m_MsgType = SSReqType_Message;
        MessagePoster poster2(&msg2, [=](qb::proto::Message& msg,
                                         qb::SSRequestMsg* stReq) {
          qb::proto::VariantMap submsg;
          submsg.setString("bond_key", m_bond.GetBondKey());
          submsg.setString("listed_market", m_bond.GetListedMarket());
          submsg.setString("market_type", NEW_DETAIL_EXCHANGE_BROKER_STRING);
          submsg.setInt32("beginDate", -1);
          submsg.setInt32("endDate",
                          qb::base::IntDate::timeToInt(time(nullptr)));
          msg.SetMap("xQBABrokerKlineDayCloseReq", submsg);
        });
        m_lReqExDealKLineIDCloseEx = poster2.send(this);
      }
      if (detailModel_DealCurveKLineCloseCFETS == type) {
        qb::SSRequestMsg msg3;
        msg3.m_pRequest = nullptr;
        msg3.m_FuncID = E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ;
        msg3.m_MsgType = SSReqType_Message;
        MessagePoster poster3(
            &msg3, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
              qb::proto::VariantMap submsg;
              submsg.setString("bond_key", m_bond.GetBondKey());
              submsg.setString("listed_market", m_bond.GetListedMarket());
              submsg.setString("market_type", NEW_DETAIL_CFETS_BROKER_STRING);
              submsg.setInt32("beginDate",
                              BondUtility::getBondDetailKlineBeginTime());
              submsg.setInt32("endDate",
                              qb::base::IntDate::timeToInt(time(nullptr)));
              msg.SetMap("xQBABrokerKlineDayCloseReq", submsg);
            });
        m_lReqExDealKLineCfetsCloseEx = poster3.send(this);
      }
    } break;
    case detailModel_DealCurveKLineCloseQuote: {
      xQBABrokerKlineDayCloseBoReq_t reqBrokerKLine;
      memset(&reqBrokerKLine, 0, sizeof(xQBABrokerKlineDayCloseBoReq_t));
      FIELDCOPY(reqBrokerKLine.m_bond_key, m_bond.GetBondKey());
      qb::base::CTime tm(ServerTimeMgr::instance().serverTime());
      int nDayTime = 24 * 60 * 60;
      int nBeginDate;
      if (m_cdcType == detailModel_CDC_Aprismt_30Day) {
        nBeginDate = qb::base::IntDate::timeToInt(tm.GetTime() - 30 * nDayTime);
      } else if (m_cdcType == detailModel_CDC_Aprismt_90Day) {
        nBeginDate = qb::base::IntDate::timeToInt(tm.GetTime() - 90 * nDayTime);
      } else if (m_cdcType == detailModel_CDC_Aprismt_HalfYear) {
        nBeginDate =
            qb::base::IntDate::timeToInt(tm.GetTime() - 182 * nDayTime);
      } else if (m_cdcType == detailModel_CDC_Aprismt_Year) {
        nBeginDate =
            qb::base::IntDate::timeToInt(tm.GetTime() - 365 * nDayTime);
      } else if (m_cdcType == detailModel_CDC_Aprismt_All) {
        nBeginDate =
            qb::base::IntDate::timeToInt(tm.GetTime() - 500 * nDayTime);
      }
      reqBrokerKLine.m_beginDate = nBeginDate;
      reqBrokerKLine.m_endDate = qb::base::IntDate::timeToInt(tm.GetTime());

      qb::SSRequestMsg msg;
      msg.m_pRequest = &reqBrokerKLine;
      msg.m_FuncID = E_FID_QBA_BROKER_KLINE_DAY_CLOSE_REQ;
      msg.m_MsgType = SSReqType_Message;
      MessagePoster poster(
          &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
            xQBABrokerKlineDayCloseBoReq_t* pData =
                (xQBABrokerKlineDayCloseBoReq_t*)stReq->m_pRequest;
            qb::proto::VariantMap submsg;
            submsg.setString("bond_key", pData->m_bond_key);
            submsg.setUint32("beginDate", pData->m_beginDate);
            submsg.setUint32("endDate", pData->m_endDate);
            msg.SetMap("xQBABrokerKlineDayCloseBoReq", submsg);
          });
      poster.send(this);
    } break;
    case detailModel_YieldCurve: {
      qb::SSRequestMsg msg;
      msg.m_pRequest = nullptr;
      msg.m_FuncID = E_FID_QBA_YIELD_CURVE_REQ_V2;
      msg.m_MsgType = SSReqType_Message;

      MessagePoster poster(
          &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
            qb::proto::VariantMap submsg;
            submsg.setString("CurveType", m_bond.GetYieldCurveType());
            submsg.setUint32("Date", 0);
            msg.SetMap("xQBAYieldCurveReq", submsg);
          });
      m_lReqYieldCurve = poster.send(this);
    } break;
    default:
      break;
  }
}

void DetailData::getSpecialCDC() {
  qb::SSRequestMsg msgCDC;
  msgCDC.m_pRequest = nullptr;
  msgCDC.m_FuncID = E_FID_QB_BOND_CDC_SPECIAL_INFO;
  MessagePoster posterIssuer(
      &msgCDC, [=](qb::proto::Message& msg, qb::SSRequestMsg*) {
        qb::proto::Message::List sublist;
        qb::proto::VariantMap listmsg;
        listmsg.setString("Bond_Type", "");
        listmsg.setString("BondID", "");
        listmsg.setString("BondKey", m_bond.GetBondKey());
        listmsg.setString("ListedMarket", m_bond.GetListedMarket());
        sublist.push_back(listmsg);
        qb::proto::VariantMap submsg;
        submsg.SetList("Bond", sublist);
        msg.SetMap("xQBBondCDCSpecialInfoReq", submsg);
      });
  posterIssuer.send(this);
}

void DetailData::reqDealData() {
  m_mapMktStreamDeal.clear();

  if (m_emCurBondType == em_Exchange) {
    if (m_ExReqDealCache.m_Bond.size() > 0) {
      qb::SSRequestMsg msg;
      msg.m_pRequest = &m_ExReqDealCache;
      msg.m_FuncID = E_FID_QB_EX_DEAL_PUSH_V2;

      MessagePoster poster(&msg, &qbbond::makeMarketStreamDealPush);
      poster.send();
    }

    if (strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) == 0) {
      return;
    }

    QBMarketStreamReq_t stReq;
    stReq.m_IndexFrom = 0;
    stReq.m_IndexTo = -1;
    memset(stReq.m_traderId, 0, sizeof(char) * 33);
    FIELDCOPY(stReq.m_bondkey, m_bond.GetBondKey());
    FIELDCOPY(stReq.m_listedmarket, m_bond.GetListedMarket());

    TW_BOND twEx;
    memset(&twEx, 0, sizeof(TW_BOND));
    FIELDCOPY(twEx.m_BondKey, m_bond.GetBondKey());
    FIELDCOPY(twEx.m_ListedMarket, m_bond.GetListedMarket());
    m_ExReqDealCache.m_Bond.push_back(twEx);

    xQBTradeCmpyInfo_c info;
    xQBTradeType_c tradeType;
    FIELDCOPY(tradeType.TradeType, "GVN");
    stReq.m_TradeTypeList.push_back(tradeType);
    FIELDCOPY(tradeType.TradeType, "TRD");
    stReq.m_TradeTypeList.push_back(tradeType);
    FIELDCOPY(tradeType.TradeType, "TKN");
    stReq.m_TradeTypeList.push_back(tradeType);

    if (m_bExchangeRight) {
      memset(&info, 0, sizeof(xQBTradeCmpyInfo_c));
      FIELDCOPY(info.m_BrokerID, "e");
      stReq.m_List.push_back(info);
      FIELDCOPY(stReq.m_exDeal, "1");  // 获取全成交
    }
    if (stReq.m_List.size() <= 0) {
      return;
    }

    qb::SSRequestMsg msg;
    msg.m_pRequest = &stReq;
    msg.m_FuncID = E_FID_QB_MARKET_STREAM_DEAL_REQ;
    MessagePoster poster(&msg, &qbbond::makeMarketStreamDealReq);
    poster.send(&BondDataCenter::instance());

    qb::SSRequestMsg msg2;
    msg2.m_pRequest = &m_ExReqDealCache;
    msg2.m_FuncID = E_FID_QB_EX_DEAL_PUSH_V2;
    MessagePoster poster2(&msg2, &qbbond::makeMarketStreamDealPush);
    poster2.send();
  } else if (m_emCurBondType == em_Broker) {
    FOR_ALL_MARKETSTREAM(0, it) {
      if (strcmp(it->m_type, "2") == 0 &&
          0 == strcmp(it->m_body.m_bondkey, m_bond.GetBondKey()) &&
          strcmp(it->m_body.m_listedmarket, m_bond.GetListedMarket()) == 0) {
        InsertMktStreamDeal(*it, m_mapMktStreamDeal);
      }
    }
  } else if (m_emCurBondType == em_CFETS) {
    if (!m_bCFETSRight ||
        (strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) != 0))
      return;

    QBMarketStreamReq_t stReq;
    stReq.m_IndexFrom = 0;
    stReq.m_IndexTo = -1;
    memset(stReq.m_traderId, 0, sizeof(char) * 33);
    FIELDCOPY(stReq.m_bondkey, m_bond.GetBondKey());
    FIELDCOPY(stReq.m_listedmarket, m_bond.GetListedMarket());

    xQBTradeType_c tradeType;
    FIELDCOPY(tradeType.TradeType, "GVN");
    stReq.m_TradeTypeList.push_back(tradeType);
    FIELDCOPY(tradeType.TradeType, "TRD");
    stReq.m_TradeTypeList.push_back(tradeType);
    FIELDCOPY(tradeType.TradeType, "TKN");
    stReq.m_TradeTypeList.push_back(tradeType);
    xQBTradeCmpyInfo_c info;

    memset(&info, 0, sizeof(xQBTradeCmpyInfo_c));
    FIELDCOPY(info.m_BrokerID, "50");
    stReq.m_List.push_back(info);

    QBQuoteQuery_t stRegister;
    TW_BOND bond;
    FIELDCOPY(bond.m_BondKey, m_bond.GetBondKey());
    FIELDCOPY(bond.m_ListedMarket, m_bond.GetListedMarket());
    stRegister.m_Bond.push_back(bond);

    qb::SSRequestMsg msg;
    msg.m_pRequest = &m_reqCFETSDeal;
    msg.m_FuncID = E_FID_QB_CFETS_DEAL_PUSH_CANCEL;
    MessagePoster poster(&msg, &qbbond::makeMarketStreamDealPush);
    poster.send();

    m_reqCFETSDeal = stRegister;

    qb::SSRequestMsg msg2;
    msg2.m_pRequest = &stReq;
    msg2.m_FuncID = E_FID_QB_CFETS_MARKET_STREAM_DEAL_REQ;
    MessagePoster poster2(&msg2, &qbbond::makeMarketStreamDealReq);
    poster2.send(this);

    qb::SSRequestMsg msg3;
    msg3.m_pRequest = &m_reqCFETSDeal;
    msg3.m_FuncID = E_FID_QB_CFETS_DEAL_PUSH;
    MessagePoster poster3(&msg3, &qbbond::makeMarketStreamDealPush);
    poster3.send();
  }
}

static void makeBestPriceSyntheticalReq(qb::proto::Message& msg,
                                        qb::SSRequestMsg* req) {
  xQBBestPriceSyntheticalReq_c* pdata =
      (xQBBestPriceSyntheticalReq_c*)req->m_pRequest;
  // 50300,债券详情页--查询发行人的财务数据,请求字段与50023相同
  qb::proto::VariantMap submsg;
  submsg.SetString("UserId", pdata->m_UserId);
  submsg.SetString("BondKey", pdata->m_BondKey);
  submsg.SetString("ListedMarket", pdata->m_ListedMarket);
  msg.SetMap("xQBBestPriceSyntheticalReq", submsg);
}

static std::string makeBestPriceSyntheticalRegParam(const CBondInfo& bond) {
  QString str = QString("%1|%2.%3")
                    .arg(E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH)
                    .arg(bond.GetBondKey())
                    .arg(bond.GetListedMarket());
  return str.toStdString();
}

void NotifyByParamBestPriceSynthetical(const qb::SSAckMsg& msg,
                                       NotifyFunc notify) {
  xQBBestPriceSyntheticalAck_c* pAck =
      (xQBBestPriceSyntheticalAck_c*)msg.m_pRet;
  if (!pAck) return;
  QString strParam = QString("%1|%2.%3")
                         .arg(msg.m_FuncID)
                         .arg(pAck->m_bondkey)
                         .arg(pAck->m_listedmarket);
  notify({msg.m_FuncID, strParam.toStdString(), nullptr}, msg);
}
void DetailData::reqAndSubBestPriceSynthetical() {
  SSRequestMsg msg;
  msg.m_FuncID = E_FID_QB_BESTPRICE_SYNTHETICAL_REQ;
  xQBBestPriceSyntheticalReq_c req;
  FIELDCOPY(req.m_UserId,
            SSUserAccountManager::instance().GetUserInfo().m_UserId);
  FIELDCOPY(req.m_BondKey, m_bond.GetBondKey());
  FIELDCOPY(req.m_ListedMarket, m_bond.GetListedMarket());
  msg.m_pRequest = &req;

  MessagePoster poster(&msg, makeBestPriceSyntheticalReq);
  poster.send(this);

  msg.m_FuncID = E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH;
  registPush({E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH,
              makeBestPriceSyntheticalRegParam(m_bond),
              NotifyByParamBestPriceSynthetical},
             &msg, makeBestPriceSyntheticalReq);
}

void DetailData::unSubBestPriceSynthetical() {
  SSRequestMsg msg;
  msg.m_FuncID = E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH_CANCEL;
  xQBBestPriceSyntheticalReq_c req;
  FIELDCOPY(req.m_UserId,
            SSUserAccountManager::instance().GetUserInfo().m_UserId);
  FIELDCOPY(req.m_BondKey, m_bond.GetBondKey());
  FIELDCOPY(req.m_ListedMarket, m_bond.GetListedMarket());
  msg.m_pRequest = &req;

  unRegistPush({E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH,
                makeBestPriceSyntheticalRegParam(m_bond), nullptr},
               &msg, makeBestPriceSyntheticalReq);
}

static std::map<int, int>
    nNewDetailPriceTab_MSindexID;  // TODO: check逻辑是否合理
void DetailData::reqMarketStream(int index) {
  if (index == 0) m_mapMktStream.clear();

  QBMarketStreamReq_t stReq;
  stReq.m_IndexFrom = index;
  stReq.m_IndexTo = -1;
  memset(stReq.m_traderId, 0, sizeof(char) * 33);
  FIELDCOPY(stReq.m_bondkey, m_bond.GetBondKey());
  FIELDCOPY(stReq.m_listedmarket, m_bond.GetListedMarket());
  bool isBondNCD = m_bond.IsBondNCD();
  // 新加服务器端获取市场动向
  // 下面的for循环中IsBrokerNCDAvailable也使用了因此这里要拷贝,之所以不一行写,是为了意图更明显
  const CBrokerList brokerListReader =
      SSUserAccountManager::instance().GetReadonlyBroker();
  const CBrokerList brokerList(brokerListReader);
  CBrokerList::BrokerMap::const_iterator itr;
  xQBTradeType_c tradeType;
  FIELDCOPY(tradeType.TradeType, "CHG");
  stReq.m_TradeTypeList.push_back(tradeType);
  log_debug("NewDetailPriceTab stReq.m_bondkey =%s", stReq.m_bondkey);
  xQBTradeCmpyInfo_c info;
  nNewDetailPriceTab_MSindexID.clear();

  for (itr = brokerList.GetBrokerMap().begin();
       itr != brokerList.GetBrokerMap().end(); itr++) {
    memset(&info, 0, sizeof(xQBTradeCmpyInfo_c));
    info.m_Id = itr->second.m_brokerID;
    FMTBUF(info.m_BrokerID, "%d", itr->second.m_brokerID);
    if (!CBrokerList::IsValidBroker(info.m_Id)) continue;
    if (isBondNCD &&
        !SSUserAccountManager::instance().IsBrokerNCDAvailable(info.m_Id))
      continue;
    if (!isBondNCD &&
        !SSUserAccountManager::instance().IsBrokerBondAvailable(info.m_Id))
      continue;
    nNewDetailPriceTab_MSindexID[info.m_Id] = 0;
    stReq.m_List.push_back(info);
  }
  if (stReq.m_List.size() <= 0) return;

  qb::SSRequestMsg msg;
  msg.m_FuncID = E_FID_QB_MARKET_STREAM_REQ;
  msg.m_pRequest = &stReq;
  MessagePoster poster(&msg, &qbbond::makeMarketStreamReq);
  poster.send(this);
}

void DetailData::reqCfetsMarketStream(int index) {
  if (index == 0) m_mapCfetsMktStream.clear();

  if (!m_bCFETSRight ||
      strcmp(m_bond.GetListedMarket(), CBondContainer::lmCIB) != 0)
    return;

  QBMarketStreamReq_t stReq;
  stReq.m_IndexFrom = index;
  stReq.m_IndexTo = -1;
  memset(stReq.m_traderId, 0, sizeof(char) * 33);
  FIELDCOPY(stReq.m_bondkey, m_bond.GetBondKey());
  FIELDCOPY(stReq.m_listedmarket, m_bond.GetListedMarket());
  xQBTradeType_c tradeType;
  FIELDCOPY(tradeType.TradeType, "CHG");
  stReq.m_TradeTypeList.push_back(tradeType);

  xQBTradeCmpyInfo_c info;
  memset(&info, 0, sizeof(xQBTradeCmpyInfo_c));
  FIELDCOPY(info.m_BrokerID, "50");
  stReq.m_List.push_back(info);

  QBQuoteQuery_t stRegister;
  TW_BOND bond;
  FIELDCOPY(bond.m_BondKey, m_bond.GetBondKey());
  FIELDCOPY(bond.m_ListedMarket, m_bond.GetListedMarket());
  stRegister.m_Bond.push_back(bond);

  qb::SSRequestMsg msg;
  msg.m_FuncID = E_FID_QB_CFETS_MARKET_STREAM_REQ_NEW;
  msg.m_pRequest = &stReq;
  MessagePoster poster(&msg, &qbbond::makeMarketStreamReq);
  poster.send(this);

  // 取消推送注册
  if (!m_reqCFETSMKt.m_Bond.empty()) {
    QBQuoteQuery_t stReq;
    stReq.m_Bond = m_reqCFETSMKt.m_Bond;
    std::vector<std::string> params =
        qbbond::getMKTPushParams(E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH, stReq);
    for (auto param : params)
      unRegistPush({E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH, param, nullptr});

    params = qbbond::getMKTPushParams(E_FID_QB_CFETS_XBOND_QUOTE_PUSH, stReq);
    for (auto param : params)
      unRegistPush({E_FID_QB_CFETS_XBOND_QUOTE_PUSH, param, nullptr});

    // 取消推送
    SSRequestMsg msgCancel;
    msgCancel.m_pRequest = &m_reqCFETSMKt;
    msgCancel.m_FuncID = E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH_CANCEL;
    {
      MessagePoster poster(&msgCancel, qbbond::makeMarketStreamDealPush);
      poster.send();
    }
    {
      msg.m_FuncID = E_FID_QB_CFETS_XBOND_QUOTE_PUSH_CANCEL;
      MessagePoster poster(&msgCancel, qbbond::makeMarketStreamDealPush);
      poster.send();
    }
  }

  m_reqCFETSMKt = stRegister;

  // 请求数据
  const int func_list[2]{E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY,
                         E_FID_QB_CFETS_XBOND_QUOTE_QUERY};
  for (int func : func_list) {
    qb::SSRequestMsg msg;
    msg.m_FuncID = func;
    QBQuoteQuery_t stReq;
    stReq.m_Bond = m_reqCFETSMKt.m_Bond;
    msg.m_pRequest = &stReq;
    MessagePoster poster(&msg, qbmsg::bond::EncodeFunc);
    poster.send(this);
  }

  // 注册推送
  {
    QBQuoteQuery_t stReq;
    stReq.m_Bond = m_reqCFETSMKt.m_Bond;
    std::vector<std::string> params =
        qbbond::getMKTPushParams(E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH, stReq);
    for (auto param : params)
      registPush({E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH, param,
                  qbbond::notifyQuotePushByParam});

    params = qbbond::getMKTPushParams(E_FID_QB_CFETS_XBOND_QUOTE_PUSH, stReq);
    for (auto param : params)
      registPush({E_FID_QB_CFETS_XBOND_QUOTE_PUSH, param,
                  qbbond::notifyQuotePushByParam});
  }
}

void DetailData::reqAppraisementData(em_NewDetail type, const char* combondKey,
                                     const CBondInfo& bondInfo) {
  // if (bondInfo.IsValidBond()) return; // ?取消判断，运行到这里都return
  int nReqFunc = -1, nReqDays = 0;
  if (!getAddDays(bondInfo, type, nReqFunc, nReqDays)) return;

  ReqDaySaveType& saveType = m_ReqAprismtDay[combondKey];

  int nBeginDate = nReqDays, nEndDate = 0;
  if (nReqFunc == E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2) {
    nEndDate = qMax(nEndDate, saveType.nCDCReqDay);
    if (nEndDate >= nBeginDate) {
      emit notifyPrimaryAprismtGetMapData();
      return;
    }
    saveType.nCDCReqDay = nBeginDate;
  } else if (nReqFunc == E_FID_QB_SQS_PRICE_SINGLE_HIS_REQ) {
    nEndDate = qMax(nEndDate, saveType.nSQSReqDay);
    if (nEndDate >= nBeginDate) return;
    saveType.nSQSReqDay = nBeginDate;

  } else {
    nEndDate = qMax(nEndDate, saveType.nZZReqDay);
    if (nEndDate >= nBeginDate) return;
    saveType.nZZReqDay = nBeginDate;
  }

  qb::base::CTimeSpan beginSpan(nBeginDate, 0, 0, 0),
      endSpan(nEndDate, 0, 0, 0);
  qb::base::CTime tmBegin, tmEnd,
      tmCurrent = qb::base::CTime(ServerTimeMgr::instance().serverTime());
  tmBegin = tmCurrent - beginSpan;
  tmEnd = tmCurrent - endSpan;

  time_t tBegin = tmBegin.GetTime(), tEnd = tmEnd.GetTime();
  reqAppraiseDataByParam(bondInfo, tBegin, tEnd, nReqFunc);
}

void DetailData::reqAppraiseDataByParam(const CBondInfo& bondInfo,
                                        time_t req_StartTime,
                                        time_t req_EndTime, int reqID) {
  QBCDCPriceSingleHisReq_t req;
  FIELDCOPY(req.m_bond_key, bondInfo.GetBondKey());
  FIELDCOPY(req.m_Listed_Market, bondInfo.GetListedMarket());
  FIELDCOPY(req.m_bond_id, bondInfo.GetBondCode());
  FIELDCOPY(req.m_Credibility, "推荐");

  req.m_DateBegin = req_StartTime;
  req.m_DateEnd = req_EndTime;

  if (reqID == E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2 &&
      (strcmp(bondInfo.GetBondSubType(), "TET") == 0 &&
       strcmp(bondInfo.GetOptionType(), "ETS") == 0)) {
    reqID = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V3;
  }

  qb::SSRequestMsg msg;
  msg.m_pRequest = &req;
  msg.m_FuncID = reqID;
  msg.m_MsgType = SSReqType_Message;
  MessagePoster poster(
      &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
        QBCDCPriceSingleHisReq_t* pData =
            (QBCDCPriceSingleHisReq_t*)stReq->m_pRequest;
        qb::proto::VariantMap submsg;
        submsg.SetString("bond_key", pData->m_bond_key);
        submsg.SetString("Listed_Market", pData->m_Listed_Market);
        submsg.SetString("bond_id", pData->m_bond_id);
        submsg.SetString("Credibility", pData->m_Credibility);
        submsg.SetInt32("DateBegin", pData->m_DateBegin);
        submsg.SetInt32("DateEnd", pData->m_DateEnd);
        submsg.SetInt32("ValueCount", pData->m_ValueCount);
        msg.SetMap("xQBCDCPriceSingleHisReq", submsg);
      });
  poster.send(this);

  FIELDCOPY(req.m_Credibility, "非推荐");

  qb::SSRequestMsg msg2;
  msg2.m_pRequest = &req;
  msg2.m_FuncID = reqID;
  msg2.m_MsgType = SSReqType_Message;
  MessagePoster poster2(
      &msg2, [=](qb::proto::Message& msg, qb::SSRequestMsg* stReq) {
        QBCDCPriceSingleHisReq_t* pData =
            (QBCDCPriceSingleHisReq_t*)stReq->m_pRequest;
        qb::proto::VariantMap submsg;
        submsg.SetString("bond_key", pData->m_bond_key);
        submsg.SetString("Listed_Market", pData->m_Listed_Market);
        submsg.SetString("bond_id", pData->m_bond_id);
        submsg.SetString("Credibility", pData->m_Credibility);
        submsg.SetInt32("DateBegin", pData->m_DateBegin);
        submsg.SetInt32("DateEnd", pData->m_DateEnd);
        submsg.SetInt32("ValueCount", pData->m_ValueCount);
        msg.SetMap("xQBCDCPriceSingleHisReq", submsg);
      });
  poster2.send(this);
}

void DetailData::onCombondKeyChanged(const char* bondKey) {
  QB_CHECK_RETURN_VOID1(bondKey && strlen(bondKey) > 0);

  if (!m_combondKey.empty() && m_hasBestQuoteRight) unSubBestPriceSynthetical();

  m_combondKey = bondKey;
  size_t pos = m_combondKey.find(".");
  if (pos != std::string::npos) {
    m_bondKey = m_combondKey.substr(0, pos);
    m_listMarket = m_combondKey.substr(pos + 1);  // TODO:HARDCODE!!!
  }
  clearData();
  if (!CBondContainer::instance().GetBondInfoByCombKey(bondKey, &m_bond)) {
    log_warning("Can't find bond : %s", bondKey);
    return;
  }

  m_shortName = QString::fromLocal8Bit(m_bond.GetBondShortName());
  m_code = m_bond.GetBondCode();
  m_firstBond = strcmp(m_bond.GetMarketType(), "2") != 0;
  setCrmType();
  fillTitleParam();
  reqBasicData();  // TODO:线程安全处理
  getCrossMarkertInfo();
  getCompanyBondInfo();

  if (m_hasBestQuoteRight) reqAndSubBestPriceSynthetical();

  emit bondChanged();
}

void DetailData::onDataArrived(const qb::SSAckMsg& msg) {
  if (msg.m_FuncID == E_FID_QB_EX_QUOTE_QUERY ||
      msg.m_FuncID == E_FID_QB_EX_QUOTE_PUSH_V2) {
    xQBExQuoteList_c* pdata = (xQBExQuoteList_c*)msg.m_pRet;
    if (pdata->m_List.empty()) {
      return;
    }
    QList<xQBExQuoteUnit_c> datas;
    for (auto iter = pdata->m_List.begin(); iter != pdata->m_List.end();
         ++iter) {
      if ((strcmp(m_bond.GetBondKey(), iter->m_BondKey) != 0) ||
          (strcmp(m_bond.GetListedMarket(), iter->m_ListedMarket) != 0)) {
        continue;
      }
      datas.append(*iter);
    }
    if (!datas.empty()) {
      emit ExchangeDataChanged(datas);
    }
  } else if (msg.m_FuncID == E_FID_QB_SHFI_SINGLE_QUOTE_REQ ||
             msg.m_FuncID == E_FID_QB_SHFI_SINGLE_QUOTE_PUSH) {
    xQBSHFIQuoteList_c* pdata = (xQBSHFIQuoteList_c*)msg.m_pRet;
    if (pdata->m_List.empty()) {
      return;
    }
    const auto iter = pdata->m_List.begin();
    // const int bondIndex =
    // CBondContainer::instance().GetBondIndex(iter->m_BondKey,
    // iter->m_ListedMarket);
    if ((strcmp(m_bond.GetBondKey(), iter->m_BondKey) != 0) ||
        (strcmp(m_bond.GetListedMarket(), iter->m_ListedMarket) != 0)) {
      return;
    }
    QList<xQBSHFIQuoteUnit_c> datas(pdata->m_List.begin(), pdata->m_List.end());
    emit SHFIDataChanged(datas);
  } else if (msg.m_FuncID == E_FID_QB_EX_BEST_QUOTE_PUSH ||
             msg.m_FuncID == E_FID_QB_EX_BEST_QUOTE_QUERY) {
    xQBBestPriceListAck_c* pdata = (xQBBestPriceListAck_c*)msg.m_pRet;

    XCQUOTE xcQuote;
    for (std::list<xQBBestPriceUnit_c>::const_iterator it =
             pdata->m_List.begin();
         it != pdata->m_List.end(); ++it) {
      // LOGDEBUG("MsgType:%d, Code:%d,Key:%s,New Version:%d
      // ",func_id,it->m_bond_code,it->m_bondkey,it->m_version);
      memset(&xcQuote, 0, sizeof(XCQUOTE));
      FIELDCOPY(xcQuote.m_sBondKey, it->m_bondkey);
      // FIELDCOPY(xcQuote.m_sBondCode,it->m_bond_code);
      FIELDCOPY(xcQuote.m_sListedMarket, it->m_listedmarket);
      xcQuote.m_time = it->m_modify_time;

      bool isValid = false;
      if (strcmp(it->m_price_status, "0") != 0) {
        if (strcmp(it->m_symbol, "1") == 0) {
          FIELDCOPY(xcQuote.m_BidPriceYield, it->m_price);  // 收益率
          FIELDCOPY(xcQuote.m_BidPriceClean,
                    it->m_clean_price);  // 净价，交易所原始报价
          FIELDCOPY(xcQuote.m_BidVol, it->m_volume);
          isValid = true;
        } else if (strcmp(it->m_symbol, "-1") == 0) {
          FIELDCOPY(xcQuote.m_OfrPriceYield, it->m_price);  // 收益率
          FIELDCOPY(xcQuote.m_OfrPriceClean,
                    it->m_clean_price);  // 净价，交易所原始报价
          FIELDCOPY(xcQuote.m_OfrVol, it->m_volume);
          isValid = true;
        }
      }

      if (isValid && SSUserAccountManager::instance().HasExchangeAuth(
                         xcQuote.m_sListedMarket)) {
        UpdateBondContainerByXCQUOTE(CBondContainer::instance(), &xcQuote, true,
                                     nullptr, 0);
      }
    }
  } else if (msg.m_FuncID == E_FID_QB_CFETS_XBOND_QUOTE_QUERY ||
             msg.m_FuncID == E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY ||
             msg.m_FuncID == E_FID_QB_CFETS_XBOND_QUOTE_PUSH ||
             msg.m_FuncID == E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH) {
    qDebug() << "DetailData::onDataArrived" << msg.m_FuncID;
    xQBBestPriceListAck_c* pdata = (xQBBestPriceListAck_c*)msg.m_pRet;

    CFETSQUOTE quote;
    for (std::list<xQBBestPriceUnit_c>::const_iterator it =
             pdata->m_List.begin();
         it != pdata->m_List.end(); ++it) {
      bool isValid = (strcmp(it->m_price_status, "0") != 0 &&
                      strcmp(it->m_bp_status, "0") == 0);
      quote.Clear();
      FIELDCOPY(quote.m_sBondKey, it->m_bondkey);
      FIELDCOPY(quote.m_sListedMarket, it->m_listedmarket);
      FIELDCOPY(quote.m_Symbol, it->m_symbol);
#ifdef WIN32
      quote.m_time = max(it->m_create_time, it->m_modify_time);
#else
      quote.m_time = std::max((int)it->m_create_time, (int)it->m_modify_time);
#endif
      if (strcmp(it->m_symbol, "1") == 0) {
        if (isValid) {
          quote.m_BidCompanyName = it->m_fin_company_name;
          FIELDCOPY(quote.m_BidPriceYield, it->m_price);
          FIELDCOPY(quote.m_BidPriceClean, it->m_clean_price);
          FIELDCOPY(quote.m_BidPriceFull, it->m_full_price);
          FIELDCOPY(quote.m_BidVol, it->m_volume);
          FIELDCOPY(quote.m_bidVolDescription, it->m_price_description);
          quote.m_bidTime = quote.m_time;
        }
        quote.m_bidversion = it->m_version;
      } else if (strcmp(it->m_symbol, "-1") == 0) {
        if (isValid) {
          quote.m_OfrCompanyName = it->m_fin_company_name;
          FIELDCOPY(quote.m_OfrPriceYield, it->m_price);
          FIELDCOPY(quote.m_OfrPriceClean, it->m_clean_price);
          FIELDCOPY(quote.m_OfrPriceFull, it->m_full_price);
          FIELDCOPY(quote.m_OfrVol, it->m_volume);
          FIELDCOPY(quote.m_ofrVolDescription, it->m_price_description);
          quote.m_ofrTime = quote.m_time;
        }
        quote.m_ofrversion = it->m_version;
      } else {
        continue;
      }

      CCFETSQuote::CFETSQUOTETYPE nType = CCFETSQuote::QINVALID;
      switch (msg.m_FuncID) {
        case E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY:  // = 50211,
                                                      // //
                                                      // 查询CFETS点击成交报价
                                                      // add by lance 2018.3.28
        case E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH:  // = 50212,
                                                     // // CFETS点击成交报价推送
                                                     // 注册
        case E_FID_QB_CFETS_QUOTE_MARKETMAKER_ALL_V2_REQ:  // = 50355,
                                                           // //CFETS行情做市报价全量请求（增量）
        case E_FID_QB_CFETS_QUOTE_MARKETMAKER_ALL_PUSH:  // = 50356,
                                                         // //CFETS行情做市报价全量注册
          nType = CCFETSQuote::MARKETMAKER;
          break;
        case E_FID_QB_CFETS_XBOND_QUOTE_QUERY:  // = 50214,
                                                // // 查询CFETS X-BOND报价 add
                                                // by lance 2018.3.28
        case E_FID_QB_CFETS_XBOND_QUOTE_PUSH:  // = 50215,
                                               // // CFETS X-BOND报价推送 注册
        case E_FID_QB_CFETS_QUOTE_XBOND_ALL_REQ:  // = 50358,
                                                  // //CFETS行情X-BOND报价全量请求（增量）
        case E_FID_QB_CFETS_XBOND_QUOTE_ALL_PUSH_V2:  // = 50359,
                                                      // //CFETS行情X-BOND报价全量注册
          nType = CCFETSQuote::XBOND;
          break;
        default:
          break;
      }
      if (nType <= CCFETSQuote::QINVALID || nType >= CCFETSQuote::QMAX) {
        return;
      }
      UpdateBondContainerByCFETSQUOTE(CBondContainer::instance(), nType,
                                      &quote);
    }

  } else if (msg.m_FuncID == E_FID_QB_HIS_SINGLE_DEAL_REQ ||
             msg.m_FuncID == E_FID_QB_HIS_SINGLE_DEAL_REG) {
    xSingleBondQuotationAck_c* qbReq = (xSingleBondQuotationAck_c*)msg.m_pRet;
    if (!qbReq) return;
    if (strcmp(m_bondKey.c_str(), qbReq->BondKey) != 0 ||
        strcmp(m_listMarket.c_str(), qbReq->ListedMarket) != 0)
      return;

    setPrice(qbReq);
    m_PreClose = qbReq->m_PreClose;
    emit hisPriceChanged();
  } else if (msg.m_FuncID == E_FID_QB_BOND_GRADE_INSTITUTION_REQ) {
    xQBBondGradeInstitutionAck* pAck = (xQBBondGradeInstitutionAck*)msg.m_pRet;
    if (!pAck) return;
    for (std::list<xQBBondGradeInstitutionUnit>::const_iterator itr =
             pAck->m_List.begin();
         itr != pAck->m_List.end(); itr++) {
      if (strcmp(m_bondKey.c_str(), itr->m_bondkey) == 0 &&
          strcmp(m_listMarket.c_str(), itr->m_listedmarket) == 0) {
        setIssuerInfo(&(*itr));
        emit issueInfoChanged();
        break;
      }
    }
  } else if (msg.m_FuncID == E_FID_QB_BOND_CDC_SPECIAL_INFO) {
    xQBBondCDCSpecialInfoListAck_c* pAck =
        (xQBBondCDCSpecialInfoListAck_c*)msg.m_pRet;
    if (!pAck) return;
    std::list<xQBBondCDCSpecialInfoUnit_c>::const_iterator itr =
        pAck->m_List.begin();
    for (; itr != pAck->m_List.end(); itr++) {
      if (strcmp(m_bondKey.c_str(), itr->m_bond_key) == 0 &&
          strcmp(m_listMarket.c_str(), itr->m_listedmarket) == 0) {
        setSpecialCDCInfo(&(*itr));
        emit cdcChanged();
        break;
      }
    }
  } else if (msg.m_FuncID == E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ) {
    xQBABrokerKlineDayCloseList_Ack* pAck =
        (xQBABrokerKlineDayCloseList_Ack*)msg.m_pRet;
    QB_CHECK_RETURN_VOID1(pAck);

    em_NewDetail type = detailModel_Default;
    if (m_lReqExDealKLineIDCloseEx == msg.m_RequestID) {
      type = detailModel_DealCurveKLineCloseEx;
    } else if (m_lReqExDealKLineIDCloseBroker == msg.m_RequestID) {
      type = detailModel_DealCurveKLineCloseBroker;
    } else if (m_lReqExDealKLineCfetsCloseEx == msg.m_RequestID) {
      type = detailModel_DealCurveKLineCloseCFETS;
    }

    std::list<xQBABrokerKlineDayCloseUnit_c>::const_iterator it =
        pAck->m_List.begin();
    if (it == pAck->m_List.end()) {
      emit dealChartKLineChanged(type);
      return;
    }

    int bondIndex = CBondContainer::instance().GetBondIndex(
        it->m_bond_key, it->m_listed_market);
    if (!CBondContainer::instance().IsValidIndex(bondIndex)) return;
    const CBondInfo& bondInfo =
        CBondContainer::instance().ElementAtR(bondIndex);

    qb::base::CTime T0(ServerTimeMgr::instance().serverTime());
    uint32_t Today = T0.GetYear() * 10000 + T0.GetMonth() * 100 + T0.GetDay();
    bool isConvertible = (strcmp(bondInfo.GetBondSubType(), "CVB") == 0 ||
                          strcmp(bondInfo.GetBondSubType(), "SCV") == 0);

    xQBABrokerKlineDayCloseList_Ack* pData = NULL;
    if (m_lReqExDealKLineIDCloseEx == msg.m_RequestID) {
      pData = BondDetailCache::instance()
                  .getChart(bondInfo.GetCombBondKey())
                  .m_pDealKlineDayCloseEx;
    } else if (m_lReqExDealKLineIDCloseBroker == msg.m_RequestID) {
      pData = BondDetailCache::instance()
                  .getChart(bondInfo.GetCombBondKey())
                  .m_pBrokerDealKlineBrokerDayClose;
    } else if (m_lReqExDealKLineCfetsCloseEx == msg.m_RequestID) {
      pData = BondDetailCache::instance()
                  .getChart(bondInfo.GetCombBondKey())
                  .m_pCfetsDealKlineCfetsDayClose;
    }
    if (!pData) {
      emit dealChartKLineChanged(type);
      return;
    }

    for (; it != pAck->m_List.end(); ++it) {
      if (it->m_Date <= Today) {
        if (isConvertible && it->m_Yield > 0)
          pData->m_List.push_back(*it);
        else if (!isConvertible && it->m_Yield <= 30)
          pData->m_List.push_back(*it);
      }
    }

    m_pDataCloseDayKline = pData;
    emit dealChartKLineChanged(type);
  } else if (msg.m_FuncID == E_FID_QBA_BROKER_KLINE_DAY_CLOSE_REQ) {
    xQBABrokerKlineDayCloseBoList_c* lstRes =
        (xQBABrokerKlineDayCloseBoList_c*)msg.m_pRet;
    if (!lstRes) return;
    std::list<xQBABrokerKlineDayCloseBoUnit_c>::const_iterator it =
        lstRes->m_List.begin();
    if (it == lstRes->m_List.end()) return;

    qb::base::CTime T0(ServerTimeMgr::instance().serverTime());
    unsigned int Today =
        T0.GetYear() * 10000 + T0.GetMonth() * 100 + T0.GetDay();

    xQBABrokerKlineDayCloseBoList_c* pData =
        BondDetailCache::instance()
            .getChart(m_bond.GetCombBondKey())
            .m_pKlintDayCloseBoList;
    if (pData == NULL) {
      emit dealChartKLineChanged(detailModel_DealCurveKLineCloseQuote);
      return;
    }

    int m_Date = 0;
    for (; it != lstRes->m_List.end(); ++it) {
      if (it->m_Date <= Today) {
        pData->m_List.push_back(*it);
      }
    }

    if (msg.m_IsReceving == 0) {
      m_pDataDayCloseBoKline = pData;
      emit dealChartKLineChanged(detailModel_DealCurveKLineCloseQuote);
    }
  } else if (msg.m_FuncID == E_FID_QB_CFETS_DEAL_DAYLINE_QUERY) {
    xQBCFETSDealDaylineAck_t* pAck = (xQBCFETSDealDaylineAck_t*)msg.m_pRet;
    QB_CHECK_RETURN_VOID1(pAck);

    em_NewDetail type = detailModel_DealCurveKLineCFETS;

    std::list<QBCFETSDealDaylineUnit>::const_iterator it = pAck->m_List.begin();
    if (it == pAck->m_List.end()) {
      emit dealChartKLineChanged(type);
      return;
    }

    int bondIndex = CBondContainer::instance().GetBondIndex(
        pAck->m_bond_key, pAck->m_listed_market);
    if (!CBondContainer::instance().IsValidIndex(bondIndex)) return;
    const CBondInfo& bondInfo =
        CBondContainer::instance().ElementAtR(bondIndex);

    qb::base::CTime T0(ServerTimeMgr::instance().serverTime());
    uint32_t Today = T0.GetYear() * 10000 + T0.GetMonth() * 100 + T0.GetDay();
    bool isConvertible = (strcmp(bondInfo.GetBondSubType(), "CVB") == 0 ||
                          strcmp(bondInfo.GetBondSubType(), "SCV") == 0);

    xQBABrokerDealKlineDayList_c* pData =
        BondDetailCache::instance()
            .getChart(bondInfo.GetCombBondKey())
            .m_pDealCurveKLineCFETS;
    if (!pData) {
      emit dealChartKLineChanged(type);
      return;
    }

    xQBABrokerDealKlineDayUnit_c unitTemp;
    FIELDCOPY(unitTemp.m_bond_key, pAck->m_bond_key);
    FIELDCOPY(unitTemp.m_listedmarket, pAck->m_listed_market);
    FIELDCOPY(unitTemp.m_Deal_type, "");

    for (; it != pAck->m_List.end(); ++it) {
      unitTemp.m_Yield = it->m_Yield;
      unitTemp.m_Date = it->m_Date;
      if (it->m_Date <= Today) {
        if (isConvertible && it->m_Yield > 0)
          pData->m_List.push_back(unitTemp);
        else if (!isConvertible && it->m_Yield <= 30)
          pData->m_List.push_back(unitTemp);
      }
    }

    m_pDataDayKline = pData;
    emit dealChartKLineChanged(type);
  } else if (msg.m_FuncID == E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ) {
    xQBABrokerDealKlineDayList_c* pAck =
        (xQBABrokerDealKlineDayList_c*)msg.m_pRet;
    QB_CHECK_RETURN_VOID1(pAck);

    em_NewDetail type = detailModel_Default;
    if (m_lReqExDealKLineIDEx == msg.m_RequestID) {
      type = detailModel_DealCurveKLineEx;
    } else if (m_lReqExDealKLineIDBroker == msg.m_RequestID) {
      type = detailModel_DealCurveKLineBroker;
    }

    std::list<xQBABrokerDealKlineDayUnit_c>::const_iterator it =
        pAck->m_List.begin();
    if (it == pAck->m_List.end()) {
      emit dealChartKLineChanged(type);
      return;
    }

    int bondIndex = CBondContainer::instance().GetBondIndex(it->m_bond_key,
                                                            it->m_listedmarket);
    if (!CBondContainer::instance().IsValidIndex(bondIndex)) return;
    const CBondInfo& bondInfo =
        CBondContainer::instance().ElementAtR(bondIndex);

    qb::base::CTime T0(ServerTimeMgr::instance().serverTime());
    uint32_t Today = T0.GetYear() * 10000 + T0.GetMonth() * 100 + T0.GetDay();
    bool isConvertible = (strcmp(bondInfo.GetBondSubType(), "CVB") == 0 ||
                          strcmp(bondInfo.GetBondSubType(), "SCV") == 0);

    xQBABrokerDealKlineDayList_c* pData = NULL;
    if (m_lReqExDealKLineIDEx == msg.m_RequestID) {
      pData = BondDetailCache::instance()
                  .getChart(bondInfo.GetCombBondKey())
                  .m_pDealCurveKLineEx;
    } else if (m_lReqExDealKLineIDBroker == msg.m_RequestID) {
      pData = BondDetailCache::instance()
                  .getChart(bondInfo.GetCombBondKey())
                  .m_pDealCurveKLineBroker;
    }
    if (!pData) {
      emit dealChartKLineChanged(type);
      return;
    }

    for (; it != pAck->m_List.end(); ++it) {
      if (it->m_Date <= Today) {
        if (isConvertible && it->m_Yield > 0)
          pData->m_List.push_back(*it);
        else if (!isConvertible && it->m_Yield <= 30)
          pData->m_List.push_back(*it);
      }
    }

    m_pDataDayKline = pData;
    emit dealChartKLineChanged(type);
  } else if (msg.m_FuncID == E_FID_QB_MARKET_STREAM_REQ)  // 市场动向
  {
    xQBMarketStreamList_c* qbReq = (xQBMarketStreamList_c*)msg.m_pRet;
    if (!qbReq) return;
    std::list<xQBMarketStreamUnit_c>::const_iterator itor =
        qbReq->m_List.begin();
    if (itor == qbReq->m_List.end()) return;
    for (; itor != qbReq->m_List.end(); itor++) {
      if (atoi(itor->m_type) == 1) {  // 动向
        if (strcmp(itor->m_body1.m_bondkey, m_bondKey.c_str()) == 0 &&
            strcmp(itor->m_body1.m_listedmarket, m_listMarket.c_str()) == 0) {
          auto it = nNewDetailPriceTab_MSindexID.find(atoi(itor->m_company_id));
          if (it != nNewDetailPriceTab_MSindexID.end()) {
            it->second = qMax(it->second, itor->m_indexID);
          } else {
            nNewDetailPriceTab_MSindexID[atoi(itor->m_company_id)] =
                itor->m_indexID;
          }
          if (m_mapMktStream.find(itor->m_indexID) != m_mapMktStream.end())
            continue;
          auto itm = m_mapMktStream.begin();
          bool bExist = false;
          for (int i = 0; i < 30 && itm != m_mapMktStream.end(); i++, itm++) {
            if (itm->second.isSameMarketStream(*itor)) {
              bExist = true;
              break;
            }
          }
          if (bExist) continue;
          m_mapMktStream.insert(std::make_pair(itor->m_indexID, *itor));
        }
      }
    }
    if (msg.m_IsReceving == 0) emit marketStreamChanged(QList<int>());
  } else if (msg.m_FuncID == E_FID_QB_CFETS_MARKET_STREAM_DEAL_REQ ||
             msg.m_FuncID == E_FID_QB_CFETS_DEAL_PUSH) {
    bool bFind = false;
    xQBMarketStreamList_c* lstResponse = (xQBMarketStreamList_c*)msg.m_pRet;
    if (!lstResponse) return;
    QList<QString> deals;
    for (std::list<xQBMarketStreamUnit_c>::const_iterator itor =
             lstResponse->m_List.begin();
         itor != lstResponse->m_List.end(); itor++) {
      if (strcmp(itor->m_type, "2") == 0 &&
          strcmp(itor->m_body2.m_bondkey, m_bondKey.c_str()) == 0 &&
          strcmp(itor->m_body2.m_listedmarket, m_listMarket.c_str()) == 0) {
        InsertMktStreamDeal(*itor, m_mapMktStreamDealCfets);
        if (msg.m_FuncID == E_FID_QB_CFETS_DEAL_PUSH)
          deals.push_back(itor->m_body2.m_id);
        bFind = true;
      }
    }

    if (bFind) {
      emit dealChartMarketDealChanged();
      emit mktStreamDealCfetsChanged(deals);
    }
  } else if (msg.m_FuncID == E_FID_QBA_YIELD_CURVE_REQ_V2) {
    if (m_lReqYieldCurve != msg.m_RequestID) {
      return;
    }

    xQBAYieldCurveList_c* qbReq = (xQBAYieldCurveList_c*)msg.m_pRet;
    if (!qbReq) return;

    if (qbReq->m_List.size() <= 0) {
      emit rateChartChanged();
      return;
    }

    BondDetailChartData& data =
        BondDetailCache::instance().getChart(m_bond.GetCombBondKey());
    if (!data.m_pYieldCurve) {
      emit rateChartChanged();
      return;
    }

    if (data.m_pYieldCurve->m_Curve.m_List.size() > 0) {
      if (strcmp(data.m_pYieldCurve->m_Curve.m_CurveType, qbReq->m_CurveType) !=
              0 ||
          strcmp(data.m_pYieldCurve->m_Curve.m_CurveName, qbReq->m_CurveName) !=
              0) {
        data.m_pYieldCurve->m_Curve.m_List.clear();
      }
    }

    if (strlen(qbReq->m_CurveType) > 0)
      FIELDCOPY(data.m_pYieldCurve->m_Curve.m_CurveType, qbReq->m_CurveType);
    if (strlen(qbReq->m_CurveName) > 0)
      FIELDCOPY(data.m_pYieldCurve->m_Curve.m_CurveName, qbReq->m_CurveName);
    data.m_pYieldCurve->m_Curve.m_Date = qbReq->m_Date;
    std::list<xQBAYieldCurveUnit_c>::iterator it = qbReq->m_List.begin();
    for (it = qbReq->m_List.begin(); it != qbReq->m_List.end(); ++it) {
      data.m_pYieldCurve->m_Curve.m_List.push_back(*it);
    }

    emit rateChartChanged();
  } else if (msg.m_FuncID == E_FID_QB_ISSUER_CREDIT_SPREAD_REQ) {
    xQBIssuerCreditSpreadAck* lstRes = (xQBIssuerCreditSpreadAck*)msg.m_pRet;
    if (!lstRes || strlen(lstRes->m_issuer_code) <= 0) return;
    QString strTemp = QString("%1").arg(lstRes->m_issuer_code);
    if (!BondDetailCache::instance().hasCache(strTemp.toStdString())) return;
    BondDetailChartData& data =
        BondDetailCache::instance().getChart(strTemp.toStdString());
    if (!data.m_pInterestIssuer) return;
    for (std::list<xQBBondCreditSpreadAckUnit>::const_iterator itr =
             lstRes->m_list.begin();
         itr != lstRes->m_list.end(); itr++) {
      data.m_pInterestIssuer->m_list.push_back(*itr);
    }
    if (msg.m_IsReceving == 0) emit interestChartChanged();
  } else if (msg.m_FuncID == E_FID_QB_BOND_CREDIT_SPREAD_REQ) {
    xQBBondCreditSpreadAck* lstRes = (xQBBondCreditSpreadAck*)msg.m_pRet;
    if (!lstRes) return;
    QString strTemp =
        QString("%1.%2").arg(lstRes->m_bond_key).arg(lstRes->m_listed_market);
    if (!BondDetailCache::instance().hasCache(strTemp.toStdString())) return;
    BondDetailChartData& data =
        BondDetailCache::instance().getChart(strTemp.toStdString());
    if (!data.m_pInterestBond) return;

    for (std::list<xQBBondCreditSpreadAckUnit>::const_iterator itr =
             lstRes->m_list.begin();
         itr != lstRes->m_list.end(); itr++) {
      data.m_pInterestBond->m_list.push_back(*itr);
    }
    if (msg.m_IsReceving == 0) emit interestChartChanged();
  } else if (msg.m_FuncID == E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2 ||
             msg.m_FuncID == E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V3) {
    int nAprsmtCmpy = KDETAIL_APRSMT_CCDVAL;
    xQBCDCPriceSingleHisAck_c* xQPrice = (xQBCDCPriceSingleHisAck_c*)msg.m_pRet;
    if (!xQPrice) return;

    QString strCombKey =
        QString("%1.%2").arg(xQPrice->m_bond_key).arg(xQPrice->m_Listed_Market);
    if (!BondDetailCache::instance().hasCache(strCombKey.toStdString())) {
      log_debug("DETAIL PAGE CANNOT FIND APP RECV BONDKEY:%s.%s",
                xQPrice->m_bond_key, xQPrice->m_Listed_Market);
      return;
    }

    if (0 == msg.m_ErrorCode) {
      updateRecommendValue(xQPrice, nAprsmtCmpy, strCombKey);
      emit cdcChartChanged();
    }
  } else if (msg.m_FuncID == E_FID_QB_CFETS_MARKET_STREAM_REQ_NEW) {
    xQBMarketStreamList_c* qbReq = (xQBMarketStreamList_c*)msg.m_pRet;
    if (!qbReq) return;
    std::list<xQBMarketStreamUnit_c>::const_iterator itor =
        qbReq->m_List.begin();
    if (itor == qbReq->m_List.end()) return;
    bool notify = false;
    for (; itor != qbReq->m_List.end(); itor++) {
      if (atoi(itor->m_type) != 1) continue;
      if (strcmp(itor->m_body1.m_bondkey, m_bondKey.c_str()) == 0 &&
          strcmp(itor->m_body1.m_listedmarket, m_listMarket.c_str()) == 0) {
        const xQBMarketStreamUnit_c& unt = *itor;
        m_mapCfetsMktStream.insert(std::make_pair(itor->m_indexID, *itor));
        notify = true;
      }
    }
    if (notify) emit cfetsMarketStreamChanged(QList<int>());
  } else if (msg.m_FuncID == E_FID_QB_BESTPRICE_SYNTHETICAL_REQ ||
             msg.m_FuncID == E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH) {
    xQBBestPriceSyntheticalAck_c* req =
        (xQBBestPriceSyntheticalAck_c*)msg.m_pRet;
    if (req != nullptr && req->m_version > m_nLastBestQuoteVersion &&
        strcmp(req->m_bondkey, m_bondKey.c_str()) == 0 &&
        strcmp(req->m_listedmarket, m_listMarket.c_str()) == 0) {
      bool canFlash = (msg.m_FuncID == E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH);
      m_nLastBestQuoteVersion = req->m_version;

      emit brokerBestQuoteChanged(req->m_bid, req->m_ofr, canFlash);
    }
  }

  if (msg.m_FuncID == E_FID_QB_EX_BEST_QUOTE_QUERY ||
      msg.m_FuncID == E_FID_QB_BEST_PRICE_PUSH_V2) {
    // 与DateCenter中的bestPriceArrived信号进行连接
    getCompanyBondInfo();
    emit crossMarketQuoteChanged();  // 不区分broker,cfets,ex
  }
}

STDMETHODIMP_(void) DetailData::OnRecover(THIS_ int32_t connect_id) {
  onCombondKeyChanged(m_combondKey.c_str());
}

void DetailData::onMarketDealChanged(
    int funcId, QString strKey,
    QList<xQBMarketStreamUnit_c> lstMarketStreamDeal) {
  if (funcId == E_FID_QB_MARKET_STREAM_DEAL_PUSH) {
    std::string strPushKey = strKey.toStdString();
    QB_CHECK_RETURN_VOID1(m_combondKey == strPushKey);

    QList<QString> deals;
    for (QList<xQBMarketStreamUnit_c>::const_iterator itor =
             lstMarketStreamDeal.begin();
         itor != lstMarketStreamDeal.end(); itor++) {
      if (strcmp(itor->m_type, "2") == 0) {
        InsertMktStreamDeal(*itor, m_mapMktStreamDeal);
        deals.push_back(itor->m_body2.m_id);
      }
    }

    if (!deals.isEmpty()) {
      emit dealChartMarketDealChanged();
      emit mktStreamDealChanged(deals);
    }
  }
}

void DetailData::clearData() {
  m_bond.Clear();
  m_titleParams.m_companyName = "";
  m_titleParams.m_strRemain = "";
  m_titleParams.m_strInterest = "";
  m_titleParams.m_strIssuer = "";
  m_titleParams.m_strIssuerInstituteName = "--";
  m_titleParams.m_strRating = "";
  m_titleParams.m_strRatingInstituteName = "--";
  m_titleParams.m_strChinaDCRating = "--";
  m_titleParams.m_strChinaDCState = "--";
  m_titleParams.m_strApp = "";
  m_titleParams.m_strZZ = "";
  m_shortName = "";
  m_code = "";
  m_titleParams.m_strAppClean = "";
  m_titleParams.m_strZZClean = "";
  m_titleParams.m_strAppDate = "";
  m_titleParams.m_strZZDate = "";
  m_titleParams.m_strIssuerName = "";
  m_titleParams.m_bShowFullPrice = false;
  m_vtCrossData.clear();
  m_mapMktStream.clear();
  m_mapCfetsMktStream.clear();
  clearPrice();
  m_brokerId = -1;
}

void DetailData::setBondInfo(CBondInfo& bi) { m_bond = bi; }

void DetailData::clearPrice() {
  m_titleParams.m_strRealPrice = "--";
  m_titleParams.m_strTrade = "--";
  m_titleParams.m_strBP = "--";
  m_titleParams.m_strYestodayPrc = "--";
  m_titleParams.m_strOpenPrc = "--";
  m_titleParams.m_strLowPrc = "--";
  m_titleParams.m_strHighPrc = "--";
  m_titleParams.m_strTKNCount = m_titleParams.m_strGVNCount =
      m_titleParams.m_strTRDCount = m_titleParams.m_strTransCount = "0";
  m_titleParams.m_clrBP = StyleMgr::instance().color("Highlight");
}

static bool IsValidPrice(const char* price) {
  return (strlen(price) > 0 && atof(price) > -0.0001);
}

void DetailData::setPrice(xSingleBondQuotationAck_c* ptrQuot) {
  clearPrice();
  // 实时行情
  if (IsValidPrice(ptrQuot->m_Price)) {
    BondUtility::FormatWholeMktDealPrice(m_titleParams.m_strRealPrice,
                                         ptrQuot->m_Price);
  }
  // TKN
  if (strcmp(ptrQuot->m_Type, "0") == 0) {
    m_titleParams.m_strTrade = "TKN";
  } else if (strcmp(ptrQuot->m_Type, "1") == 0) {
    m_titleParams.m_strTrade = "GVN";
  } else if (strcmp(ptrQuot->m_Type, "2") == 0) {
    m_titleParams.m_strTrade = "TRD";
  }

  // BP
  if (IsValidPrice(ptrQuot->m_Price) && IsValidPrice(ptrQuot->m_PreClose)) {
    double dbPrc = atof(ptrQuot->m_Price), dbYesPrc = atof(ptrQuot->m_PreClose);
    if ((dbPrc > 29.9999 && dbYesPrc > 29.9999) ||
        (dbPrc < 30 && dbYesPrc < 30)) {
      double dbBp = dbPrc - dbYesPrc;
      QString strTemp, strAdd = "";
      if (dbPrc < 30) {
        strAdd = "BP";  // ENGLISH
      }
      if (dbBp > 0.0001 || dbBp < -0.0001) {
        if (dbPrc < 30) dbBp *= 100;
        strTemp = QString::number(dbBp, 'f', 2);
        m_titleParams.m_strBP = SSTools::PriceRemoveZero(strTemp) + strAdd;
        if (dbBp > 0.0001) {
          m_titleParams.m_strBP = "+" + m_titleParams.m_strBP;
          m_titleParams.m_clrBP = StyleMgr::instance().color("Down_Reduce_H1");
        } else {
          m_titleParams.m_clrBP = StyleMgr::instance().color("Up_Increase_H1");
        }
      } else {
        m_titleParams.m_strBP = "0BP";
      }
    }
  }
  // 昨收
  if (IsValidPrice(ptrQuot->m_PreClose)) {
    BondUtility::FormatWholeMktDealPrice(m_titleParams.m_strYestodayPrc,
                                         ptrQuot->m_PreClose);
  }
  // 开盘
  if (IsValidPrice(ptrQuot->m_Open)) {
    BondUtility::FormatWholeMktDealPrice(m_titleParams.m_strOpenPrc,
                                         ptrQuot->m_Open);
  }
  // 最高
  if (IsValidPrice(ptrQuot->m_High)) {
    BondUtility::FormatWholeMktDealPrice(m_titleParams.m_strHighPrc,
                                         ptrQuot->m_High);
  }
  // 最低
  if (IsValidPrice(ptrQuot->m_Low)) {
    BondUtility::FormatWholeMktDealPrice(m_titleParams.m_strLowPrc,
                                         ptrQuot->m_Low);
  }
  m_titleParams.m_strTransCount = QString::number(ptrQuot->m_TransCount);
  m_titleParams.m_strTKNCount = QString::number(ptrQuot->m_TKNCount);
  m_titleParams.m_strGVNCount = QString::number(ptrQuot->m_GVNCount);
  m_titleParams.m_strTRDCount = QString::number(ptrQuot->m_TRDCount);
}

void DetailData::setIssuerInfo(const xQBBondGradeInstitutionUnit* unt) {
  // TODO ENGLISH
  m_titleParams.m_strIssuerInstituteName =
      QString::fromLocal8Bit(unt->m_Issuer_Rating_Dept);
  m_titleParams.m_strRatingInstituteName =
      QString::fromLocal8Bit(unt->m_Rating_Current_Dept);
  if (m_titleParams.m_strIssuerInstituteName.isEmpty())
    m_titleParams.m_strIssuerInstituteName = "--";
  if (m_titleParams.m_strRatingInstituteName.isEmpty())
    m_titleParams.m_strRatingInstituteName = "--";
}

static QString strEstRemark(int i) {
  switch (i) {
    case 0: {
      return QObject::tr("行权/到期", "EstRemark");
    }
    case 1: {
      return QObject::tr("行权", "EstRemark");
    }
    case 2: {
      return QObject::tr("到期", "EstRemark");
    }
    case 3: {
      return QObject::tr("", "EstRemark");
    }
    case 4: {
      return QObject::tr("/", "EstRemark");
    }
    default:
      break;
  }
  return "";
}

void DetailData::setSpecialCDCInfo(const xQBBondCDCSpecialInfoUnit_c* unt) {
  QString strKey = QString::fromLocal8Bit(unt->m_bond_key) + "." +
                   QString::fromLocal8Bit(unt->m_listedmarket);
  int bondIndex =
      BondUtility::getFirstIssueBondInfo(strKey.toStdString().c_str());
  if (!CBondContainer::instance().IsValidIndex(bondIndex)) return;

  const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
  bool bIsCDCAuthValid = bi.IsCDCAuthValid();
  int nOptType = CBondCDCPriceInfo::est_type_invalid;
  m_titleParams.m_bShowFullPrice = false;
  if (unt->m_BondProperty == 1 ||
      (unt->m_BondProperty == 0 && m_crmType != 0)) {
    if (unt->m_BondProperty == 1) {
      m_titleParams.m_bShowFullPrice = true;
      // m_bViolate = true; 暂时不显示违约券
      m_titleParams.m_strApp = QString::fromLocal8Bit(unt->m_CDCYield);
      if (strlen(unt->m_CDCFullPrice) > 0 &&
          (atof(unt->m_CDCFullPrice) > 0.0001 ||
           atof(unt->m_CDCFullPrice) < -0.0001)) {
        m_titleParams.m_strAppClean =
            QString::fromLocal8Bit(unt->m_CDCFullPrice);
      }
    } else {  // crm cln或者标的
      if (strlen(unt->m_CDCYield) > 0) {
        m_titleParams.m_bShowFullPrice = true;
        m_titleParams.m_strApp = QString::fromLocal8Bit(unt->m_CDCYield);
        if (strlen(unt->m_CDCFullPrice) > 0 &&
            (atof(unt->m_CDCFullPrice) > 0.0001 ||
             atof(unt->m_CDCFullPrice) < -0.0001)) {
          // TODO: ENGLISH
          m_titleParams.m_strAppClean =
              QString::fromLocal8Bit(unt->m_CDCFullPrice) + "(元)";
        } else
          m_titleParams.m_strAppClean = "--";
      }
    }
    m_titleParams.m_strAppDate = FormatAppDate(unt->m_Date);
    CBondCDCPriceInfo::instance().GetCDCPriceLast(
        nOptType, bIsCDCAuthValid, bondIndex,
        CBondCDCPriceInfo::price_type_yield, true);
  } else {
    m_titleParams.m_strApp = QString::fromLocal8Bit(
        CBondCDCPriceInfo::instance()
            .GetCDCPriceLast(nOptType, bIsCDCAuthValid, bondIndex,
                             CBondCDCPriceInfo::price_type_yield, true)
            .c_str());
    m_titleParams.m_strAppClean = QString::fromLocal8Bit(
        CBondCDCPriceInfo::instance()
            .GetCDCPriceLast(nOptType, bIsCDCAuthValid, bondIndex,
                             CBondCDCPriceInfo::price_type_clean, true)
            .c_str());
    if (!m_titleParams.m_strApp.isEmpty())
      m_titleParams.m_strAppDate = FormatAppDate(
          CBondCDCPriceInfo::instance().GetEstimateDate(bondIndex));
  }
  if (m_titleParams.m_strApp.isEmpty()) m_titleParams.m_strApp = "--";
  QString strRemark = strEstRemark(1 + nOptType);
  if (!strRemark.isEmpty()) m_titleParams.m_strApp += ("(" + strRemark + ")");
}

bool DetailData::getAddDays(const CBondInfo& bondInfo, em_NewDetail type,
                            int& func, int& reqDays) {
  bool bReturn = true;
  tm ltmp;
  qb::base::CTime timeCrt(ServerTimeMgr::instance().serverTime());
  timeCrt.GetLocalTm(&ltmp);

  switch (type) {
    case detailModel_CDC_Aprismt_30Day: {
      func = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2;
      reqDays = 29;
    } break;
    case detailModel_CDC_Aprismt_HalfYear: {
      func = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2;
      reqDays = 182;
    } break;
    case detailModel_CDC_Aprismt_Year: {
      func = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2;
      reqDays = ltmp.tm_yday;
    } break;
    case detailModel_CDC_Aprismt_90Day: {
      func = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2;
      reqDays = 89;
    } break;
    case detailModel_CDC_Aprismt_All: {
      func = E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2;
      reqDays = 500;
    } break;
    case detailModel_SQS_Aprismt_30Day: {
      func = E_FID_QB_SQS_PRICE_SINGLE_HIS_REQ;
      reqDays = APRISMT_REQ_30DAY - 1;
    } break;
    case detailModel_SQS_Aprismt_HalfYear: {
      func = E_FID_QB_SQS_PRICE_SINGLE_HIS_REQ;
      reqDays = APRISMT_REQ_HALFYEAR - 1;
    } break;
    case detailModel_SQS_Aprismt_Year: {
      func = E_FID_QB_SQS_PRICE_SINGLE_HIS_REQ;
      reqDays = ltmp.tm_yday;
    } break;
    case detailModel_ZZ_Aprismt_30Day: {
      func = E_FID_QB_ZZ_PRICE_SINGLE_HIS_REQ;
      reqDays = APRISMT_REQ_30DAY - 1;
    } break;
    case detailModel_ZZ_Aprismt_Year: {
      func = E_FID_QB_ZZ_PRICE_SINGLE_HIS_REQ;
      reqDays = ltmp.tm_yday;
    } break;
    default: {
      bReturn = false;
      break;
    }
  }

  if (func ==
      E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2) {  // 无中债估值历史权限,显示30天
    int nMax = 29;
    if (bondInfo.IsCDCAuthValid()) {
      nMax = qMax(29, ltmp.tm_yday);  // 不足30天显示30天
    }
    auto& auth = SSUserAccountManager::instance().GetCDCAutority();
    if (auth.find(10) != auth.end()) {
      nMax = 500;
    }
    reqDays = qMin(reqDays, nMax);
  } else if (func == E_FID_QB_ZZ_PRICE_SINGLE_HIS_REQ) {
    if (!SSUserAccountManager::instance().GetCSIAuthorityFlag()) {
      return false;
    }
  }

  return bReturn;
}

void DetailData::updateRecommendValue(xQBCDCPriceSingleHisAck_c* priceData,
                                      int nAprsmtCmpy,
                                      const QString& strCombKey) {
  if (!priceData) return;

  std::list<xQBCDCPriceSingleHis_c>::iterator lIter =
      priceData->m_PriceList.begin();
  std::list<xQBCDCPriceSingleHis_c>::iterator lIterEnd =
      priceData->m_PriceList.end();
  bool bRecommendFlag = false;

  BondDetailChartData& dataCDCHIS =
      BondDetailCache::instance().getChart(strCombKey.toStdString());
  if (!dataCDCHIS.m_pAaprismtHisData) {
    dataCDCHIS.m_pAaprismtHisData = new BondAprismtHistoryData;
  }

  std::map<unsigned int, DetailAppraisementPriceData>* l_MapData = NULL;
  switch (nAprsmtCmpy) {
    case KDETAIL_APRSMT_CCDVAL:
      l_MapData = &(dataCDCHIS.m_pAaprismtHisData->m_CDCPriceCtner);
      break;
    case KDETAIL_APRSMT_ZZVAL:
      l_MapData = &(dataCDCHIS.m_pAaprismtHisData->m_ZZPriceCtner);
      break;
    case KDETAIL_APRSMT_SQSVAL:
      l_MapData = &(dataCDCHIS.m_pAaprismtHisData->m_SCHPriceCtner);
      break;
    default:
      return;
      break;
  }

  for (; lIter != lIterEnd; ++lIter) {
    if (strcmp(lIter->m_Credibility, "") == 0) /*"非推荐"*/
    {
      bRecommendFlag = false;
    } else {
      bRecommendFlag = true;
    }

    if (false == bRecommendFlag) {
      unsigned int l_Time = qb::base::IntDate::timeToInt(lIter->m_Date);
      std::map<unsigned int, DetailAppraisementPriceData>::iterator l_find =
          l_MapData->find(l_Time);
      _UnRecommendPriceDataType l_UnRecommendData;
      l_UnRecommendData.m_CleanPrice = lIter->m_CleanPrice;
      l_UnRecommendData.m_Yield = lIter->m_Yield;
      l_UnRecommendData.m_Modified_Duration = lIter->m_Modified_Duration;
      l_UnRecommendData.m_Convexity = lIter->m_Convexity;
      l_UnRecommendData.m_Basis_Point_Value = lIter->m_Basis_Point_Value;
      l_UnRecommendData.m_Spread_Duration = lIter->m_Spread_Duration;
      l_UnRecommendData.m_Spread_Convexity = lIter->m_Spread_Convexity;
      FIELDCOPY(l_UnRecommendData.m_Credibility, lIter->m_Credibility);
      FIELDCOPY(l_UnRecommendData.m_cdcExercise, lIter->m_cdcExercise);
      if (l_find != l_MapData->end()) {
        l_find->second.m_UnRecommendData = l_UnRecommendData;
      } else {
        DetailAppraisementPriceData lDetailData;
        lDetailData.m_RecommendAllData = *lIter;
        lDetailData.m_RecommendAllData.m_CleanPrice = 0;
        lDetailData.m_RecommendAllData.m_Yield = 0;
        lDetailData.m_RecommendAllData.m_Modified_Duration = 0;
        lDetailData.m_RecommendAllData.m_Convexity = 0;
        lDetailData.m_RecommendAllData.m_Basis_Point_Value = 0;
        lDetailData.m_RecommendAllData.m_Spread_Duration = 0;
        lDetailData.m_RecommendAllData.m_Spread_Convexity = 0;
        memset(lDetailData.m_RecommendAllData.m_Credibility, 0,
               sizeof(lDetailData.m_RecommendAllData.m_Credibility));
        lDetailData.m_RecommendAllData.m_Credibility[0] = '\0';
        lDetailData.m_UnRecommendData = l_UnRecommendData;
        l_MapData->insert(std::make_pair(l_Time, lDetailData));
      }
    } else {
      unsigned int l_Time = qb::base::IntDate::timeToInt(lIter->m_Date);
      std::map<unsigned int, DetailAppraisementPriceData>::iterator l_find =
          l_MapData->find(l_Time);
      if (l_find != l_MapData->end()) {
        l_find->second.m_RecommendAllData = *lIter;
      } else {
        DetailAppraisementPriceData lDetailData;
        lDetailData.m_RecommendAllData = *lIter;
        l_MapData->insert(std::make_pair(l_Time, lDetailData));
      }
    }
  }
}

bool DetailData::InsertMktStreamDeal(
    const MarketStreamInfo& mktInfo,
    std::map<std::string, xQBMarketStreamUnit_c>& dealmap) {
  if (BondDetailTools::IsValidateTime(
          qMax(mktInfo.m_create_time, mktInfo.m_modify_time))) {
    xQBMarketStreamUnit_c infoUnit;
    BondDetailTools::ConvFromMktStmInfo(mktInfo, infoUnit);
    return InsertMktStreamDeal(infoUnit, dealmap);
  }
  return false;
}

bool DetailData::InsertMktStreamDeal(
    const xQBMarketStreamUnit_c& mktInfo,
    std::map<std::string, xQBMarketStreamUnit_c>& dealmap) {
  bool bReturn = false;
  int nState = atoi(mktInfo.m_body2.m_dealStatus);
  if (BondDetailTools::IsValidateTime(
          qMax(mktInfo.m_create_time, mktInfo.m_modify_time))) {
    if (dealmap.find(mktInfo.m_body2.m_id) == dealmap.end()) {
      if (nState >= 0 && nState <= 3 || nState == 8) {
        dealmap.insert(std::make_pair(mktInfo.m_body2.m_id, mktInfo));
        bReturn = true;
      }
    } else {
      if (nState == 8 || (nState >= 0 && nState <= 3)) {
        dealmap[mktInfo.m_body2.m_id] = mktInfo;
      } else {
        dealmap.erase(mktInfo.m_body2.m_id);
      }
      bReturn = true;
    }
  }
  return bReturn;
}
